Ejemplo n.º 1
0
    def startCreate( self, view ):
        '''Sets the state of the context to begin editing the active goal.

        @param      view        A pointer to the OpenGL viewer.
        '''
        if ( self.state == self.POINT ):
            self.editGoal = Goals.PointGoal()
            self.editGoal.set( self.downWorld[0], self.downWorld[1] )
            self.goalEditor.activeGoal = self.goalEditor.addGoal( self.goalEditor.editSet, self.editGoal )
            self.startEdit( view )
        elif ( self.state == self.CIRCLE ):
            self.editGoal = Goals.CircleGoal()
            self.editGoal.set( self.downWorld[0], self.downWorld[1], 0.0 )
            self.goalEditor.activeGoal = self.goalEditor.addGoal( self.goalEditor.editSet, self.editGoal )
            self.startEdit( view )
        elif ( self.state == self.AABB ):
            self.editGoal = Goals.AABBGoal()
            self.editGoal.set( self.downWorld[0], self.downWorld[1], self.downWorld[0], self.downWorld[1] )
            self.goalEditor.activeGoal = self.goalEditor.addGoal( self.goalEditor.editSet, self.editGoal )
            self.state = self.AABB
            self.startEdit( view )
        elif ( self.state == self.OBB ):
            self.editGoal = Goals.OBBGoal()
            self.editGoal.set( self.downWorld[0], self.downWorld[1], 0.0, 0.0, 0.0 )
            self.goalEditor.activeGoal = self.goalEditor.addGoal( self.goalEditor.editSet, self.editGoal )
            self.state = self.OBB
            self.startEdit( view )
def main():
    protocol = r'../protocols/SampleGoal.xml'
    #protocol_file = r'SampleGoal.xml'
    protocol_name = os.path.join(os.path.dirname(__file__), protocol)

    tree = xml.etree.ElementTree.parse(protocol_name)
    for g in tree.findall('//goals/roi'):
        print 'Adding goal ' + Goals.print_goal(g, 'xml')
        Goals.add_goal(g, connect.get_current('Plan'))
    ui = connect.get_current('ui')
    ui.TitleBar.MenuItem['Plan Optimization'].Click()
    ui.TitleBar.MenuItem['Plan Optimization'].Popup.MenuItem[
        'Plan Optimization'].Click()
    ui.Workspace.TabControl['DVH'].TabItem['Clinical Goals'].Select()
Ejemplo n.º 3
0
    def newSet(self):
        '''Creates a new goal set, returns its index.

        @returns        The index of the new goal set.
        '''
        id = len(self.goalSets)

        badIDs = map(lambda x: x.id, self.goalSets)
        badIDs.sort()
        newID = badIDs[-1] + 1
        gs = Goals.GoalSet()
        gs.id = newID
        self.goalSets.append(gs)
        return id
Ejemplo n.º 4
0
            if roi_name == '':
                for roi in case.PatientModel.RegionsOfInterest:
                    if (g.find('name').text in response['oars'] and
                        roi.Name == response['oars'][g.find('name').text]['structure']) or \
                            (g.find('name').text in response['targets'] and
                             roi.Name == response['targets'][g.find('name').text]['structure']):
                        roi_name = roi.Name
                        break

            # If this structure was found and the number of fractions match
            if roi_name != '':
                c += 1
                Goals.add_goal(goal=g,
                               roi=roi_name,
                               targets=response['targets'],
                               plan=plan,
                               exam=exam,
                               case=case)

    if c > 0:
        patient.Save()
        ui = connect.get_current('ui')
        ui.TitleBar.MenuItem['Plan Optimization'].Click()
        ui.TitleBar.MenuItem['Plan Optimization'].Popup.MenuItem[
            'Plan Optimization'].Click()
        ui.Workspace.TabControl['DVH'].TabItem['Clinical Goals'].Select()
        ui.ToolPanel.TabItem._Scripting.Select()
        connect.await_user_input(
            'Customize the clinical goals now, then continue the script')

    status.next_step(
Ejemplo n.º 5
0
                            format(g.find('name').text))
                    try:
                        g.find('dose').text = str(know_goal['dose'])
                        logging.debug('Dose changed for ROI {} to {}'.format(
                            g.find('name').text,
                            g.find('dose').text))
                    except KeyError:
                        logging.debug(
                            'knowledge goals for {} had no dose information'.
                            format(g.find('name').text))
                    try:
                        g.find('volume').text = str(know_goal['volume'])
                        g.find('volume').attrib['units'] = str(
                            know_goal['units'])
                        logging.debug('Index changed for ROI {} to {}'.format(
                            g.find('name').text,
                            g.find('volume').text))
                    except KeyError:
                        logging.debug(
                            'knowledge goals for {} had no volume information'.
                            format(g.find('name').text))

                # except AttributeError:
                #    logging.debug('Goal loaded which does not have dose attribute.')
                # Regardless, add the goal now
                Goals.add_goal(g, connect.get_current('Plan'))


if __name__ == '__main__':
    main()
Ejemplo n.º 6
0
def main():
    import optparse
    parser = optparse.OptionParser()
    parser.add_option("-r",
                      "--roadmap",
                      help="Optional roadmap file to load",
                      action="store",
                      dest="roadmapName",
                      default='')
    parser.add_option("-g",
                      "--goals",
                      help="Optional goal definition file to load",
                      action="store",
                      dest="goalsName",
                      default='')
    parser.add_option("-b",
                      "--obstacle",
                      help="Optional obstacle file to load.",
                      action="store",
                      dest='obstName',
                      default='')
    parser.add_option("-a",
                      "--agent",
                      help="Optional agent position file to load.",
                      action="store",
                      dest='agtName',
                      default='')
    parser.add_option("-f",
                      "--field",
                      help="Optional vector field file to load.",
                      action="store",
                      dest='fieldName',
                      default='')
    parser.add_option(
        "-c",
        "--createField",
        help=
        'Creates a field based on the domain of the obstacles - ignored if --field(-f) is specified',
        action='store_true',
        dest='createField',
        default=False)
    parser.add_option("-s",
                      "--scb",
                      help="Optional scb file to load.",
                      action="store",
                      dest='scbName',
                      default='')
    parser.add_option(
        "-i",
        "--inDir",
        help=
        "Optional directory to find input files - only applied to file names with relative paths",
        action="store",
        dest='inDir',
        default='.')
    parser.add_option(
        "-o",
        "--outDir",
        help=
        "Optional directory to write output files - only applied to file names with relative paths",
        action="store",
        dest='outDir',
        default='.')
    parser.add_option(
        '--region',
        help=
        'Specify the bounding region of the action.  If provided, it will set the initial camera properties.  Format is minX minY maxX maxY',
        nargs=4,
        type='float',
        dest='boundRegion',
        default=None)
    options, args = parser.parse_args()

    paths.setInDir(options.inDir)
    paths.setOutDir(options.outDir)
    obstName = paths.getPath(options.obstName)
    agtName = paths.getPath(options.agtName)
    roadmapName = paths.getPath(options.roadmapName)
    fieldName = paths.getPath(options.fieldName)
    scbName = paths.getPath(options.scbName)
    goalsName = paths.getPath(options.goalsName)
    print "Arguments:"
    print "\tInput dir: ", options.inDir
    print "\tOutput dir:", options.outDir
    print "\tobstacles: ", obstName
    print "\tagents:    ", agtName
    print "\troad map:  ", roadmapName
    print "\tfield:     ", fieldName
    print "\tscbName:   ", scbName
    print "\tGoals:     ", goalsName
    if (obstName):
        obstacles, bb = readObstacles(obstName)
    else:
        obstacles = ObstacleSet()
        bb = AABB()
        if (not options.boundRegion is None):
            bb.min = Vector3(options.boundRegion[0], options.boundRegion[1], 0)
            bb.max = Vector3(options.boundRegion[2], options.boundRegion[3], 0)
            print bb
        else:
            bb.min = Vector3(-100, -100, 0)
            bb.max = Vector3(100, 100, 0)

    agents = AgentSet(0.23)
    if (agtName):
        agents.initFromFile(agtName)
        if (scbName != ''):
            # This reads the agent radius from the file, but no longer visualizes the agents
            # This is a bit of a hack.  It would be better to simply disable drawing the
            #   agents when the scb playback context is active.  But I don't have the time
            #   to figure out an elegant solution to this.
            agents.clear()

    if (fieldName):
        field = GLVectorField((0, 0), (1, 1), 1)
        field.read(fieldName)
    elif (options.createField):
        print "Instantiate vector field from geometry:", bb
        bbSize = bb.max - bb.min
        field = GLVectorField((bb.min.x, bb.min.y), (bbSize.y, bbSize.x), 2.0)
    else:
        field = None

    graph = Graph()
    if (roadmapName):
        graph.initFromFile(roadmapName)

    # create viewer
    pygame.init()
    fontname = pygame.font.get_default_font()
    font = pygame.font.Font(fontname, 12)

    w = bb.max.x - bb.min.x
    h = bb.max.y - bb.min.y
    view = View((w, h), (bb.min.x, bb.min.y), (w, h), (bb.min.x, bb.min.y),
                (800, 600), font)
    view.HELP_TEXT = 'View controls:' + \
                     '\n\tpan - Ctrl + left mouse button' + \
                     '\n\tzoom in - mouse wheel up' + \
                     '\n\tzoom out - mouse wheel down' + \
                     '\n\tzoom - Shift + left mouse button (up and down)'
    view.initWindow('Create roadmap')
    pygame.key.set_repeat(250, 10)
    view.initGL()

    if (field):
        field.newGLContext()


##    field = None

# load goals
    if (goalsName):
        try:
            goalSets = Goals.readGoals(goalsName)
        except ValueError as e:
            print "Error parsing goals:", str(e)
            print "\tUsing empty GoalSet"
            goalSets = [Goals.GoalSet()]
    else:
        goalSets = [Goals.GoalSet()]
    goalVis = GoalEditor(goalSets)

    context = ContextSwitcher()
    context.addContext(PositionContext(), pygame.K_q)
    context.addContext(GoalContext(goalVis), pygame.K_g)
    context.addContext(AgentContext(agents), pygame.K_a)
    context.addContext(ObstacleContext(obstacles), pygame.K_o)
    if (field):
        context.addContext(FieldEditContext(field), pygame.K_f)
    if (scbName != ''):
        context.addContext(SCBContext(scbName, obstacles, agents.defRadius),
                           pygame.K_s)
    context.newGLContext()

    redraw = True
    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
                break
            elif (event.type == pygame.MOUSEMOTION
                  or event.type == pygame.MOUSEBUTTONUP
                  or event.type == pygame.MOUSEBUTTONDOWN):
                result = handleMouse(event, context, view, graph, obstacles,
                                     agents, field)
                redraw |= result.needsRedraw()
            elif (event.type == pygame.KEYDOWN or event.type == pygame.KEYUP):
                try:
                    result = handleKey(event, context, view, graph, obstacles,
                                       agents, field)
                    redraw |= result.needsRedraw()
                except Exception as e:
                    print "Error with keyboard event"
                    print "\t", e
                    running = False
            elif (event.type == pygame.VIDEORESIZE):
                view.resizeGL(event.size)
                if (field):
                    field.newGLContext()
                context.newGLContext()
                redraw |= True
            elif (event.type == pygame.VIDEOEXPOSE):
                redraw |= True
        if (redraw):
            drawGL(view, context, obstacles, graph, agents, field, goalVis)
            message(view, updateMsg(agents.count()))
            pygame.display.flip()
            if (context):
                name = context.exportDisplay()
                if (name):
                    pygame.image.save(view.surface, name)
            redraw = False
    writeRoadmap()
Ejemplo n.º 7
0
def pdf(patient, exam, plan, folder=report_folder, fields=None, overwrite=True, priority=4):
    tic = time.time()
    filename = os.path.join(folder, '{}_{}.pdf'.format(patient.Name.replace('^', '_'), plan.Name))
    if overwrite and os.path.isfile(filename):
        logging.debug('Deleting existing file per overwrite flag')
        os.remove(filename)

    # Initialize Platypus document
    logging.debug('Initializing PDF to save to {}'.format(filename))
    doc = BaseDocTemplate(filename,
                          pagesize=letter,
                          pageTemplates=[PageTemplate(id='all',
                                                      frames=[Frame(0.75 * inch, 0.75 * inch, 7 * inch, 9.5 * inch,
                                                                    showBoundary=0)])],
                          showBoundary=0,
                          rightMargin=0.75 * inch,
                          leftMargin=0.75 * inch,
                          bottomMargin=0.75 * inch,
                          topMargin=0.75 * inch,
                          allowSplitting=1,
                          title='Treatment Planning Order',
                          encrypt=None)

    # Define text style
    s = ParagraphStyle({'fontName': 'Helvetica',
                        'fontSize': 10,
                        'leading': 10,
                        'leftIndent': 0,
                        'rightIndent': 0,
                        'firstLineIndent': 0,
                        'encoding': 'Unicode',
                        'alignment': TA_LEFT,
                        'spaceBefore': 0,
                        'spaceAfter': 0,
                        'bulletFontName': 'Helvetica',
                        'bulletFontSize': 10,
                        'bulletIndent': 0,
                        'textColor': colors.black,
                        'backColor': None,
                        'wordWrap': None,
                        'borderWidth': 0,
                        'borderPadding': 0,
                        'borderColor': None,
                        'borderRadius': None,
                        'allowWidows': 1,
                        'allowOrphans': 0,
                        'textTransform': None,
                        'endDots': None,
                        'splitLongWords': 1,
                        'bulletAnchor': 'start',
                        'justifyLastLine': 0,
                        'justifyBreaks': 0})

    # Start report
    story = [Table(data=[[Image(os.path.join(os.path.dirname(__file__), 'report_logo.jpg'),
                                width=2 * inch,
                                height=0.4306 * inch),
                          P('<b><font size=14>' + fields['protocol'] + ' Treatment Planning Order</font></b>', s)]],
                   colWidths=[2.5 * inch, 5 * inch],
                   spaceAfter=0.25 * inch,
                   hAlign='LEFT',
                   style=TableStyle([('VALIGN', (0, 0), (-1, -1), 'MIDDLE')]))]

    # Retrieve CT info
    info = exam.GetAcquisitionDataFromDicom()
    story.append(Table(data=[[P('<b>Name:</b>', s), P(patient.Name.replace('^', ' '), s)],
                             [P('<b>Patient ID:</b>', s), P(patient.PatientID, s)],
                             [P('<b>Date of Birth:</b>', s), P('{}/{}/{}'.format(patient.DateOfBirth.Month,
                                                                                 patient.DateOfBirth.Day,
                                                                                 patient.DateOfBirth.Year), s)],
                             [P('<b>Clinic:</b>', s), P(fields['institution'], s)],
                             [P('<b>Diagnosis:</b>', s), P(' '.join(fields['diagnosis']), s)],
                             [P('<b>Order:</b>', s), P(fields['order'], s)],
                             [P('<b>Planning Image:</b>', s), P('{}, {} {}'.
                                                                format(exam.Name,
                                                                       info['EquipmentModule']['InstitutionName'],
                                                                       info['EquipmentModule']['StationName']), s)],
                             [P('<b>Plan Name:</b>', s), P(plan.Name, s)]
                             ],
                       colWidths=[1.5 * inch, 5 * inch],
                       spaceAfter=0.25 * inch,
                       hAlign='LEFT',
                       style=TableStyle([('VALIGN', (0, 0), (-1, -1), 'TOP')])))

    # If a fields dict was not provided, query the provided plan
    if fields is None:
        fields = {'plans': [], 'fractions': [], 'technique': []}
        for b in plan.BeamSets:
            fields['plans'].append(b.DicomPlanLabel)
            fields['fractions'].append(b.FractionationPattern.NumberOfFractions)
            fields['technique'].append(b.DeliveryTechnique)

    # Generate plan details table
    details_header = [P('<b>Plan Details</b>', s)]
    for p in fields['plans']:
        details_header.append(P('<b>{}</b>'.format(p.replace('_R0A0', '_RXAX')), s))

    details = list([details_header])
    details.append([P('Number of Fractions', s)])
    for n in range(len(fields['plans'])):
        if len(fields['fractions']) > n and fields['fractions'][n] is not None:
            details[-1].append(P('{}'.format(fields['fractions'][n]), s))

        else:
            details[-1].append(details[-1][-1])

    if 'technique' in fields and len(fields['technique']) > 0 and fields['technique'][0] is not None:
        details.append([P('Technique', s)])
        for n in range(len(fields['plans'])):
            details[-1].append(P(fields['technique'][min(n, len(fields['technique'])-1)], s))

    if 'frequency' in fields and len(fields['frequency']) > 0 and fields['frequency'][0] is not None:
        details.append([P('Treatment frequency', s)])
        for n in range(len(fields['plans'])):
            details[-1].append(P(fields['frequency'][min(n, len(fields['frequency']) - 1)], s))

    if 'imaging' in fields and len(fields['imaging']) > 0 and fields['imaging'][0] is not None:
        details.append([P('Image guidance', s)])
        for n in range(len(fields['plans'])):
            details[-1].append(P(fields['imaging'][min(n, len(fields['imaging']) - 1)], s))

    if 'motion' in fields and len(fields['motion']) > 0 and fields['motion'][0] is not None:
        details.append([P('Motion management', s)])
        for n in range(len(fields['plans'])):
            details[-1].append(P(fields['motion'][min(n, len(fields['motion']) - 1)], s))

    width = min(1.5, 4.5 / len(details[0])) * inch
    story.append(Table(data=details,
                       colWidths=[1.5 * inch] + [width] * len(fields['plans']),
                       spaceAfter=0.25 * inch,
                       repeatRows=1,
                       hAlign='LEFT',
                       style=TableStyle([('BOX', (0, 0), (-1, -1), 0.25, colors.black),
                                         ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black),
                                         ('BACKGROUND', (0, 0), (-1, 0), colors.lightblue),
                                         ('VALIGN', (0, 0), (-1, -1), 'TOP')])))

    # Generate target table
    if 'targets' in fields:
        target_header = [P('<b>Target Dose</b>', s)]
        for p in fields['plans']:
            target_header.append(P('<b>{}</b>'.format(p.replace('_R0A0', '_RXAX')), s))

        if len(fields['plans']) > 1:
            target_header.append(P('<b>Composite</b>', s))

        targets = [target_header]
        for t in fields['targets'].keys():
            if fields['targets'][t]['use']:
                targets.append([P(t, s)])
                c = 0
                for n in range(len(fields['plans'])):
                    if len(fields['targets'][t]['dose']) > n and fields['targets'][t]['dose'][n] > 0:
                        targets[-1].append(P('{} Gy @ {} Gy/fx'.format(fields['targets'][t]['dose'][n],
                                                                       fields['targets'][t]['dose'][n] /
                                                                       fields['fractions'][n]), s))
                        c += fields['targets'][t]['dose'][n]

                    else:
                        targets[-1].append(P(' ', s))

                if len(fields['plans']) > 1:
                    targets[-1].append(P('{} Gy'.format(c), s))

        story.append(Table(data=targets,
                           colWidths=[1.5 * inch] + [width] * (len(targets[0]) - 1),
                           spaceAfter=0.25 * inch,
                           repeatRows=1,
                           hAlign='LEFT',
                           style=TableStyle([('BOX', (0, 0), (-1, -1), 0.25, colors.black),
                                             ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black),
                                             ('BACKGROUND', (0, 0), (-1, 0), colors.lightblue),
                                             ('VALIGN', (0, 0), (-1, -1), 'TOP')])))

    # Generate goals table
    goals_header = [P('<b>Clinical Goals</b>', s)]
    if len(fields['plans']) == 1:
        goals_header.append(P('<b>{}</b>'.format(fields['plans'][0].replace('_R0A0', '_RXAX')), s))

    else:
        goals_header.append(P('<b>Composite</b>', s))

    goals_header.append(P('<b>Priority</b>', s))
    goals_dict = {}
    c = 0
    for f in plan.TreatmentCourse.EvaluationSetup.EvaluationFunctions:
        try:
            c += 1
            if f.PlanningGoal.Priority < priority:
                goal = Goals.print_goal(f, 'eval')
                if goal != '':
                    if '{}{}'.format(f.PlanningGoal.Priority, f.ForRegionOfInterest.Name) in goals_dict:
                        goals_dict['{}{}'.format(f.PlanningGoal.Priority,
                                                 f.ForRegionOfInterest.Name)][1] += '<br/>' + goal

                    else:
                        goals_dict['{}{}'.format(f.PlanningGoal.Priority, f.ForRegionOfInterest.Name)] = \
                            [f.ForRegionOfInterest.Name, goal, f.PlanningGoal.Priority]

                else:
                    logging.warning('Unrecognized type for clinical goal {}'.format(c))

        except Exception:
            logging.warning('An error occurred adding clinical goal {}'.format(c))

    goals = [goals_header]
    oars = []
    for k in sorted(goals_dict.keys()):
        goals.append([P(goals_dict[k][0], s), P(goals_dict[k][1], s), P('{}'.format(goals_dict[k][2]), s)])
        if len(oars) < 5 and ('targets' not in fields or goals_dict[k][0] not in fields['targets']):
            oars.append(goals_dict[k][0])

    story.append(Table(data=goals,
                       colWidths=[1.5 * inch + width * (len(targets[0]) - 2)] + [width] + [0.75 * inch],
                       spaceAfter=0.25 * inch,
                       repeatRows=1,
                       hAlign='LEFT',
                       style=TableStyle([('BOX', (0, 0), (-1, -1), 0.25, colors.black),
                                         ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black),
                                         ('BACKGROUND', (0, 0), (-1, 0), colors.lightblue),
                                         ('VALIGN', (0, 0), (-1, -1), 'TOP')])))

    # Add billing justification
    modality = '3D'
    for b in plan.BeamSets:
        if b.Modality == 'Photons' and b.PlanGenerationTechnique == 'Imrt':
            modality = 'IMRT'
            break

    justification = 'To avoid complication-inducing doses to the '
    if len(oars) > 1:
        justification += '{} and {}'.format(', '.join(oars[0:-1]), oars[-1])
    elif len(oars) > 0:
        justification += oars[0]
    else:
        justification = 'To avoid excessive dose heterogeneity within the target'

    story.append(Table(data=[[P('<b>Date of Service: </b>', s), P(time.strftime('%m/%d/%Y %I:%M %p',
                                                                                time.localtime()), s)],
                             [P('<b>Reason for {}: </b>'.format(modality), s), P(justification, s)]],
                       colWidths=[1.5 * inch, 5 * inch],
                       spaceAfter=0.25 * inch,
                       hAlign='LEFT',
                       style=TableStyle([('VALIGN', (0, 0), (-1, -1), 'TOP')])))

    # Add plan options
    if 'options' in fields:
        options = []
        for o in sorted(fields['options'].iterkeys()):
            if fields['options'][o]:
                options.append([P('[X]', s), P(o, s)])

            else:
                options.append([P('[&nbsp;&nbsp;]', s), P(o, s)])

        if len(options) > 0:
            options[0].insert(0, P('<b>Plan Options:</b>', s))
            for i in range(1, len(options)):
                options[i].insert(0, P('', s))

        story.append(Table(data=options,
                           colWidths=[1.5 * inch, 0.35 * inch, 4.65 * inch],
                           spaceAfter=0.25 * inch,
                           hAlign='LEFT',
                           style=TableStyle([('VALIGN', (0, 0), (-1, -1), 'TOP')])))

    # Add comments
    if 'comments' in fields and fields['comments'].strip() != '':
        story.append(Table(data=[[P('<b>Comments:</b>', s), P(fields['comments'].replace('\n', '<br/>'), s)]],
                           colWidths=[1.5 * inch, 5 * inch],
                           spaceAfter=0.25 * inch,
                           hAlign='LEFT',
                           style=TableStyle([('VALIGN', (0, 0), (-1, -1), 'TOP')])))

    # Finish up
    doc.build(story)
    logging.debug('WriteTpo.pdf() completed successfully in {:.3f} seconds'.format(time.time() - tic))
    return filename