<commit_before>"""
calculatepi.py
Author: Nils Kingston
Credit: Roger
Assignment:

Write and submit a Python program that computes an approximate value of π by calculating the following sum:

(see: https://github.com/HHS-IntroProgramming/Calculate-Pi/blob/master/README.md)

This sum approaches the true value of π as n approaches ∞.

Your program must ask the user how many terms to use in the estimate of π, how many decimal places,
then print the estimate using that many decimal places. Exactly like this:

I will estimate pi. How many terms should I use? 100
How many decimal places should I use in the result? 7
The approximate value of pi is 3.1315929

Note: remember that the printed value of pi will be an estimate!

"""
print("I will estimate pi")
n = int(input("How many terms should I use? "))
decimal = int(input("How many decimal places should I use in the result? "))

p = 4 * sum([((-1.0)**k)/(2 * k + 1) for k in range(0,n)])
print("The approximate value of pi is {0:.{1}f}".format(p, decimal))

<commit_msg>Updated from Brython Server: 9/14/2015 2:27:27 PM<commit_after>"""
calculatepi.py
Author: Nils Kingston
Credit: Roger
Assignment:

Write and submit a Python program that computes an approximate value of π by calculating the following sum:

(see: https://github.com/HHS-IntroProgramming/Calculate-Pi/blob/master/README.md)

This sum approaches the true value of π as n approaches ∞.

Your program must ask the user how many terms to use in the estimate of π, how many decimal places,
then print the estimate using that many decimal places. Exactly like this:

I will estimate pi. How many terms should I use? 100
How many decimal places should I use in the result? 7
The approximate value of pi is 3.1315929

Note: remember that the printed value of pi will be an estimate!

"""
n = int(input("I will estimate pi. How many terms should I use? "))

decimal = int(input("How many decimal places should I use in the result? "))

p = 4 * sum([((-1.0)**k)/(2 * k + 1) for k in range(0,n)])
print("The approximate value of pi is {0:.{1}f}".format(p, decimal))

<|endoftext|>


<commit_before>#!/usr/bin/env python

import os
import pygame
from pygame.locals import *
import subprocess
import sys
import time

# 1000% dependent on picam installed and running as a service
PICAM_HOME = '/home/pi/picam'
# these are all in seconds
RECORDING_LENGTH = 30
AFTER_PAUSE_LENGTH = 10
PRE_RECORDING_COUNTDOWN_LENGTH = 3

# colors
BLACK = (0,0,0)
RED = (200,0,0)

# standard text sizes
TINY_TEXT = 20
SMALL_TEXT = 30
STANDARD_TEXT = 60
LARGE_TEXT = 90

pygame.init()
pygame.mouse.set_visible(False)
screen = pygame.display.set_mode((800,480),pygame.FULLSCREEN)
background = pygame.Surface(screen.get_size())
background = background.convert()
clock = pygame.time.Clock()

def checkForPicam():
  """If picam isn't running, this is all wasted"""
  try:
    subprocess.check_output(["pgrep", "picam"])
  except:
    sys.exit("Picam isn't running?")

def startRecording():
  """Touch a start recording hook for picam"""
  print("start recording")
  open('%s/hooks/start_record' % PICAM_HOME, 'w').close()
  screen.fill(RED)
  pygame.display.update()

def stopRecording():
  """Touch a stop recording hook for picam"""
  print("stop recording")
  open('%s/hooks/stop_record' % PICAM_HOME, 'w').close()
  screen.fill(BLACK)
  pygame.display.update()

def countDown(message=None, timer=30, color=RED, bg=BLACK):
  """Show a count down message and timer to the display"""
  for tick in range(0, timer):
    nmessage = "%s: %i" % (message, (timer - tick))
    updateDisplay(nmessage, STANDARD_TEXT, color, bg)
    time.sleep(1)
    #updateDisplay("")
    #time.sleep(.4)

def updateDisplay(message=None, size=STANDARD_TEXT, color=RED, bg=BLACK):
  """Update the display optionally with a message"""
  background.fill(bg)
  font = pygame.font.Font(None, size)
  text = font.render(message, 1, color)
  textpos = text.get_rect()
  textpos.centerx = background.get_rect().centerx
  textpos.centery = background.get_rect().centery
  background.blit(text, textpos)
  screen.blit(background, (0,0))
  pygame.display.update()

def flashDisplay(message=None, flashes=5, size=STANDARD_TEXT, color=RED, bg=RED):
  """Flash a message to the display"""
  for flash in range(0, flashes):
    updateDisplay(message, size, color, bg)
    time.sleep(.6)
    updateDisplay("")
    time.sleep(.4)

def record():
  """Record the recording"""
  updateDisplay("Get ready to record!", STANDARD_TEXT, RED)
  time.sleep(2)
  updateDisplay("You have %i seconds" % RECORDING_LENGTH, STANDARD_TEXT, RED)
  time.sleep(2)
  countDown("Recording in", PRE_RECORDING_COUNTDOWN_LENGTH, RED, BLACK)
  startRecording()
  countDown("Recording", RECORDING_LENGTH, BLACK, RED)
  stopRecording()
  updateDisplay("Thank you", LARGE_TEXT)
  time.sleep(AFTER_PAUSE_LENGTH)
  updateDisplay("#fuckyourburn", TINY_TEXT)
  time.sleep(.5)
  updateDisplay("Touch the screen to tell your story", STANDARD_TEXT)

def main_loop():
  """Main Loop"""
  updateDisplay("Touch the screen to tell your story", STANDARD_TEXT)
  while True:
    clock.tick(15)
    for event in pygame.event.get():
      if event.type == pygame.MOUSEBUTTONDOWN:
        #print(event)
        record()

if __name__ == "__main__":
  checkForPicam()
  flashDisplay("Loading...", 3, STANDARD_TEXT, RED, BLACK)
  main_loop()
<commit_msg>massive cleanup and rework, thanks josh<commit_after>#!/usr/bin/env python

import pygame
from pygame.locals import *
import subprocess
import sys
import time

# 1000% dependent on picam installed and running as a service
PICAM_HOME = '/home/pi/picam'
# these are all in seconds
RECORDING_LENGTH = 30
AFTER_PAUSE_LENGTH = 2
PRE_RECORDING_COUNTDOWN_LENGTH = 3

# colors
BLACK = (0, 0, 0)
RED = (200, 0, 0)

# standard text sizes
TINY_TEXT = 20
SMALL_TEXT = 30
STANDARD_TEXT = 60
LARGE_TEXT = 90

pygame.init()
pygame.mouse.set_visible(False)
pygame.event.set_allowed(None)
# since this is running on a touch screen, we only care about mouse clicks
pygame.event.set_allowed(pygame.MOUSEBUTTONDOWN)
screen = pygame.display.set_mode((800, 480), pygame.FULLSCREEN)
background = pygame.Surface(screen.get_size())
background = background.convert()
clock = pygame.time.Clock()

def checkForPicam():
  """If picam isn't running, this is all wasted"""
  try:
    subprocess.check_output(["pgrep", "picam"])
  except:
    sys.exit("Picam isn't running?")

def isRecording():
  """The picam state file is our best resource for the current state"""
  f = open("%s/state/record" % PICAM_HOME, "r")
  state = f.readline()
  f.close()
  return state == "true"

def clearQueue(caller):
  """Pygame seems to queue up events and so to prevent many rapid
     loops, we clear it all by calling get and clear"""
  print("clearQueue called from %s: %i events cleared" % (caller, len(pygame.event.get())))
  pygame.event.clear()

def startRecording():
  """Touch a start recording hook for picam"""
  print("start recording")
  clearQueue("startRecording")

  updateDisplay("Get ready to record!", STANDARD_TEXT, RED)
  time.sleep(2)
  updateDisplay("You have %i seconds" % RECORDING_LENGTH, STANDARD_TEXT, RED)
  time.sleep(2)

  countDown("Recording in", STANDARD_TEXT, PRE_RECORDING_COUNTDOWN_LENGTH, RED, BLACK)

  open('%s/hooks/start_record' % PICAM_HOME, 'w').close()
  screen.fill(RED)

  countDown("Touch the screen to stop recording at any time", SMALL_TEXT, RECORDING_LENGTH, BLACK, RED)

  updateDisplay("Thank you", LARGE_TEXT)
  time.sleep(AFTER_PAUSE_LENGTH)
  updateDisplay("Touch the screen to tell your story", STANDARD_TEXT)
  pygame.display.update()

def stopRecording():
  """Touch a stop recording hook for picam"""
  print("stop recording")
  clearQueue("StopRecording")
  open('%s/hooks/stop_record' % PICAM_HOME, 'w').close()

def countDown(message=None, size=STANDARD_TEXT, timer=30, color=RED, bg=BLACK):
  """Show a count down message and timer to the display"""
  clearQueue("countDown")
  for tick in range(0, timer):
    nmessage = "%s: %i" % (message, (timer - tick))
    print(nmessage)
    updateDisplay(nmessage, size, color, bg)
    if isRecording() and pygame.event.peek(MOUSEBUTTONDOWN):
      print("recording was cancelled")
      return()
    time.sleep(1)

def updateDisplay(message=None, size=STANDARD_TEXT, color=RED, bg=BLACK):
  """Update the display optionally with a message"""
  background.fill(bg)
  font = pygame.font.Font(None, size)
  text = font.render(message, 1, color)
  textpos = text.get_rect()
  textpos.centerx = background.get_rect().centerx
  textpos.centery = background.get_rect().centery
  background.blit(text, textpos)
  screen.blit(background, (0, 0))
  pygame.display.update()

def flashDisplay(message=None, flashes=5, size=STANDARD_TEXT, color=RED, bg=RED):
  """Flash a message to the display"""
  for flash in range(0, flashes):
    print(message)
    updateDisplay(message, size, color, bg)
    time.sleep(.6)
    updateDisplay("")
    time.sleep(.4)

def main_loop():
  """Main Loop"""
  # this should never really happen but does during development where we quit
  # out and the recording continues
  if isRecording():
    print("Camera was already recording, stopping")
    stopRecording()
  updateDisplay("Touch the screen to tell your story", STANDARD_TEXT)
  while True:
    clock.tick(30)
    event = pygame.event.wait()
    clearQueue("main_loop")
    if isRecording():
      stopRecording()
    else:
      startRecording()

if __name__ == "__main__":
  checkForPicam()
  flashDisplay("Loading...", 3, STANDARD_TEXT, RED, BLACK)
  main_loop()
<|endoftext|>


<commit_before>#!/usr/bin/env python

import os
#import datetime as dt
#from pygame.locals import *
#from signal import pause
import pygame
import time
#from subprocess import Popen

# 1000% dependent on picam installed and running as a service
picam_home = '/home/pi/picam'

pygame.init()
#pygame.mouse.set_visible(False)
screen = pygame.display.set_mode((800,480),pygame.FULLSCREEN)
background = pygame.Surface(screen.get_size())
background = background.convert()
clock = pygame.time.Clock()

# colors
black = (0,0,0)
white = (255,255,255)
red = (200,0,0)
bright_red = (255,0,0)
green = (0,200,0)
bright_green = (0,255,0)

# standard text sizes
tiny_text = 20
small_text = 30
standard_text = 60
large_text = 90

def startRecording():
  """Touch a start recording hook for picam"""
  print("start recording")
  screen.fill(red)
  pygame.display.update()
  open('%s/hooks/start_record' % picam_home, 'w').close()

def stopRecording():
  """Touch a stop recording hook for picam"""
  print("stop recording")
  screen.fill(black)
  pygame.display.update()
  open('%s/hooks/stop_record' % picam_home, 'w').close()

def countDown(message, timer=30, color=red, bg=black):
  """Flash a count down message and timer to the display"""
  for tick in range(0, timer):
    nmessage = "%s: %i" % (message, (timer - tick))
    updateDisplay(nmessage, standard_text, color, bg)
    time.sleep(.6)
    updateDisplay("")
    time.sleep(.4)

def updateDisplay(message, size=standard_text, color=red, bg=black):
  """Update the display optionally with a message"""
  background.fill(bg)
  font = pygame.font.Font(None, size)
  text = font.render(message, 1, color)
  textpos = text.get_rect()
  textpos.centerx = background.get_rect().centerx
  textpos.centery = background.get_rect().centery
  background.blit(text, textpos)
  screen.blit(background, (0,0))
  pygame.display.update()

def flashDisplay(message, flashes=5, size=standard_text, color=red, bg=red):
  """Flash a message to the display"""
  for flash in range(0, flashes):
    updateDisplay(message, size, color, bg)
    time.sleep(.6)
    updateDisplay("")
    time.sleep(.4)

def button(msg,x,y,w,h,ic,ac,action=None):
  mouse = pygame.mouse.get_pos()
  click = pygame.mouse.get_pressed()
  print(click)
  if x+w > mouse[0] > x and y+h > mouse[1] > y:
    pygame.draw.rect(screen, ac,(x,y,w,h))

    if click[0] == 1 and action != None:
      action()
  else:
    pygame.draw.rect(screen, ic,(x,y,w,h))

  smallText = pygame.font.Font(None, tiny_text)
  textSurf, textRect = text_objects(msg, smallText)
  textRect.center = ( (x+(w/2)), (y+(h/2)) )
  screen.blit(textSurf, textRect)

def game_loop():
  updateDisplay("Get ready to record!", standard_text, red)
  time.sleep(2)
  updateDisplay("You have 30 seconds", standard_text, red)
  countDown("Recording in", 3, red, black)
  startRecording()
  countDown("Recording", 30, black, red)
  stopRecording()
  updateDisplay("Thank you", large_text)
  time.sleep(10)
  updateDisplay("#fuckyourburn", tiny_text)
  time.sleep(.5)

def quitgame():
  pygame.quit()

def text_objects(text, font):
  textSurface = font.render(text, True, black)
  return textSurface, textSurface.get_rect()

def game_intro():
  intro = True
  updateDisplay("Touch screen to begin", standard_text)
  while intro:
    for event in pygame.event.get():
      print(event)
      if event.type == pygame.QUIT:
        pygame.quit()
        quit()

      updateDisplay("Ready to tell your story?", standard_text)
      button("GO!",150,400,100,50,green,bright_green,game_loop)
      button("Quit",550,400,100,50,red,bright_red,quitgame)

      pygame.display.update()
      clock.tick(60)

flashDisplay("Loading...", 3, standard_text, red, black)
game_intro()
game_loop()
pygame.quit()
quit()
<commit_msg>remove all buttons<commit_after>#!/usr/bin/env python

import os
#import datetime as dt
#from pygame.locals import *
#from signal import pause
import pygame
import time
#from subprocess import Popen

# 1000% dependent on picam installed and running as a service
picam_home = '/home/pi/picam'

recording_length = 3

pygame.init()
#pygame.mouse.set_visible(False)
screen = pygame.display.set_mode((800,480),pygame.FULLSCREEN)
background = pygame.Surface(screen.get_size())
background = background.convert()
clock = pygame.time.Clock()

# colors
black = (0,0,0)
white = (255,255,255)
red = (200,0,0)
bright_red = (255,0,0)
green = (0,200,0)
bright_green = (0,255,0)

# standard text sizes
tiny_text = 20
small_text = 30
standard_text = 60
large_text = 90

def startRecording():
  """Touch a start recording hook for picam"""
  print("start recording")
  screen.fill(red)
  pygame.display.update()
  open('%s/hooks/start_record' % picam_home, 'w').close()

def stopRecording():
  """Touch a stop recording hook for picam"""
  print("stop recording")
  screen.fill(black)
  pygame.display.update()
  open('%s/hooks/stop_record' % picam_home, 'w').close()

def countDown(message, timer=30, color=red, bg=black):
  """Flash a count down message and timer to the display"""
  for tick in range(0, timer):
    nmessage = "%s: %i" % (message, (timer - tick))
    updateDisplay(nmessage, standard_text, color, bg)
    time.sleep(1)
    #updateDisplay("")
    #time.sleep(.4)

def updateDisplay(message, size=standard_text, color=red, bg=black):
  """Update the display optionally with a message"""
  background.fill(bg)
  font = pygame.font.Font(None, size)
  text = font.render(message, 1, color)
  textpos = text.get_rect()
  textpos.centerx = background.get_rect().centerx
  textpos.centery = background.get_rect().centery
  background.blit(text, textpos)
  screen.blit(background, (0,0))
  pygame.display.update()

def flashDisplay(message, flashes=5, size=standard_text, color=red, bg=red):
  """Flash a message to the display"""
  for flash in range(0, flashes):
    updateDisplay(message, size, color, bg)
    time.sleep(.6)
    updateDisplay("")
    time.sleep(.4)

def record():
  """Record the recording"""
  updateDisplay("Get ready to record!", standard_text, red)
  time.sleep(2)
  updateDisplay("You have 30 seconds", standard_text, red)
  time.sleep(2)
  countDown("Recording in", 3, red, black)
  startRecording()
  countDown("Recording", recording_length, black, red)
  stopRecording()
  updateDisplay("Thank you", large_text)
  time.sleep(10)
  updateDisplay("#fuckyourburn", tiny_text)
  time.sleep(.5)
  updateDisplay("Touch the screen to tell your story", standard_text)

def main_loop():
  """Main Loop"""
  updateDisplay("Touch the screen to tell your story", standard_text)
  while True:
    clock.tick(15)
    for event in pygame.event.get():
      if event.type == pygame.MOUSEBUTTONDOWN:
        print(event)
        record()

#flashDisplay("Loading...", 3, standard_text, red, black)
#game_intro()
#game_loop()
main_loop()
#pygame.quit()
#quit()
<|endoftext|>


<commit_before>import copy
import json
import os

import requests

BASE_URL = "https://%s.capsulecrm.com/api/"

class ImproperlyConfigured(Exception):
    pass

class CapsuleCRM(object):
    def __init__(self, cap_name=None, cap_key=None):
        env = os.environ
        self.cap_name = cap_name or env.get('CAPSULE_NAME')
        self.cap_key = cap_key or env.get('CAPSULE_KEY')
        if not self.cap_name or not self.cap_key:
            raise ImproperlyConfigured('Missing capsule subdomain name')
        self.auth = requests.auth.HTTPBasicAuth(self.cap_key, self.cap_name)
        self.base_url = BASE_URL % self.cap_name
        self.headers = {
            'accept': 'application/json',
            'content-type': 'application/json'
        }
        self.path = []
        self.qs = {}
        self.method = 'get'

    def __getattr__(self, method):
        # Create a new copy of self
        obj = self._copy()
        # add method to path
        obj.path.append(method)
        return obj.mock_attr

    def _copy(self):
        obj = self.__class__(self.cap_name, self.cap_key)
        obj.path = copy.copy(self.path)
        obj.qs = copy.copy(self.qs)
        return obj

    def mock_attr(self, *args, **kwargs):
        """
        Empty method to call to slurp up args and kwargs.

        `args` get pushed onto the url path.
        `kwargs` are converted to a query string and appended to the URL.
        """
        self.path.extend(args)
        self.qs.update(kwargs)
        return self

    @property
    def url(self):
        url = self.base_url + '/'.join(map(str, self.path))
        return url

    @property
    def request(self):
        args = (self.method, self.url)
        kwargs = {
            'auth': self.auth,
            'headers': self.headers,
        }
        if self.method == 'get':
            kwargs['params'] = self.qs
        else:
            kwargs['data'] = json.dumps(self.qs)

        return requests.request(*args, **kwargs)

    def get(self):
        self.method = 'get'
        return self.request

    def post(self):
        self.method = 'post'
        return self.request

    def put(self):
        self.method = 'put'
        return self.request

    def delete(self):
        self.method = 'delete'
        return self.request

    @property
    def json(self):
        """Short cut to json. Only works for GET requests.

        cap.party().json instead of cap.part().get().json

        """
        return getattr(self, self.method)().json
<commit_msg>Add explicit query string<commit_after>import copy
import json
import os

import requests

BASE_URL = "https://%s.capsulecrm.com/api/"

class ImproperlyConfigured(Exception):
    pass

class CapsuleCRM(object):
    def __init__(self, cap_name=None, cap_key=None):
        env = os.environ
        self.cap_name = cap_name or env.get('CAPSULE_NAME')
        self.cap_key = cap_key or env.get('CAPSULE_KEY')
        if not self.cap_name or not self.cap_key:
            raise ImproperlyConfigured('Missing capsule subdomain name')
        self.auth = requests.auth.HTTPBasicAuth(self.cap_key, self.cap_name)
        self.base_url = BASE_URL % self.cap_name
        self.headers = {
            'accept': 'application/json',
            'content-type': 'application/json'
        }
        self.path = []
        self.qs = {}
        self.method = 'get'
        self.explicit_qs = {}  # needed for posting with a query string

    def __getattr__(self, method):
        # Create a new copy of self
        obj = self._copy()
        # add method to path
        obj.path.append(method)
        return obj.mock_attr

    def _copy(self):
        obj = self.__class__(self.cap_name, self.cap_key)
        obj.path = copy.copy(self.path)
        obj.qs = copy.copy(self.qs)
        return obj

    def mock_attr(self, *args, **kwargs):
        """
        Empty method to call to slurp up args and kwargs.

        `args` get pushed onto the url path.
        `kwargs` are converted to a query string and appended to the URL.
        """
        self.path.extend(args)
        self.qs.update(kwargs)
        return self

    def set_qs(self, data=None, **kwargs):
        """Set the explicit query string"""
        if data is not None:
            kwargs.update(data)
        self.explicit_qs.update(kwargs)
        return self

    @property
    def url(self):
        url = self.base_url + '/'.join(map(str, self.path))
        return url

    @property
    def request(self):
        args = (self.method, self.url)
        kwargs = {
            'auth': self.auth,
            'headers': self.headers,
        }
        if self.method == 'get':
            kwargs['params'] = self.qs
        else:
            kwargs['data'] = json.dumps(self.qs)
            kwargs['params'] = self.explicit_qs

        return requests.request(*args, **kwargs)

    def get(self):
        self.method = 'get'
        return self.request

    def post(self):
        self.method = 'post'
        return self.request

    def put(self):
        self.method = 'put'
        return self.request

    def delete(self):
        self.method = 'delete'
        return self.request

    @property
    def json(self):
        """Short cut to json. Only works for GET requests.

        cap.party().json instead of cap.part().get().json

        """
        return getattr(self, self.method)().json
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

#from django.utils.translation import ugettext_lazy as _
from django.db import models
#from django.conf import settings
#from tagging.fields import TagField
#from django.db.models import permalink

#import copy
#from decimal import Decimal
import datetime

from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
import string, random
import decimal
from utils import get_order_detail_class, OrderDetailNotAvailable

# Any items to be added to the cart must implement the following interface.
# CartProductInterface is the minimal one; it does nothing.
# DefaultCartProductInterface implements sensible defaults.

class CartProductInterface(object):
    """Minimal CartProductInterface implementation, raising NotImplementedError
    for all required methods."""
    def get_thumbnail(self, options={}):
        raise NotImplementedError()

    def get_price(self, quantity, options={}):
        raise NotImplementedError()

    @staticmethod
    def get_shipping_cost(items, options={}):
        raise NotImplementedError()

    @staticmethod
    def get_available_shipping_options(items):
        raise NotImplementedError()

    @staticmethod
    def verify_purchase(items):
        raise NotImplementedError()

class DefaultCartProductInterface(CartProductInterface):
    """CartProductInterface interface implementation, giving sensible defaults for
    all required methods."""
    def get_thumbnail(self, options={}):
        return None

    @staticmethod
    def get_shipping_cost(items, options={}):
        return 0

    @staticmethod
    def get_available_shipping_options(items):
        return None

    @staticmethod
    def verify_purchase(items):
        return True

ORDER_STATUSES = [
    ('pending', 'Pending'),
    ('confirmed', 'Confirmed'),
    ('shipped', 'Shipped'),
]

class Order(models.Model):
    hash = models.CharField(max_length=16, unique=True, editable=False)
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)
    email = models.EmailField(default='', blank=True)
    phone = models.CharField(max_length=20, default='', blank=True)
    street_address = models.CharField(max_length=255)
    suburb = models.CharField(max_length=255, blank=True, default='')
    city = models.CharField(max_length=255)
    post_code = models.PositiveIntegerField(max_length=20)
    country = models.CharField(max_length=255)

    status = models.CharField(max_length=20, choices=ORDER_STATUSES, default='pending')
    payment_successful = models.BooleanField(default=False)
    notification_sent = models.BooleanField(default=False, editable=False)
    acknowledgement_sent = models.BooleanField(default=False, editable=False)

    creation_date = models.DateTimeField(auto_now_add=True)
    payment_date = models.DateTimeField(null=True, blank=True, help_text="Leave blank to auto-fill this field")
    completion_date = models.DateTimeField(null=True, blank=True, help_text="Leave blank to auto-fill this field")
    session_id = models.CharField(max_length=32, editable=False)

    shipping_cost = models.DecimalField(max_digits=8, decimal_places=2, default=0)

    class Meta:
        ordering = ('-creation_date',)

    def __unicode__(self):
        return "Order #%s - %s %s, %s" % (self.pk, self.first_name, self.last_name, self.total())

    def save(self):
        if (not self.completion_date) and self.status == 'shipped':
            self.completion_date = datetime.datetime.now()
        if (not self.payment_date) and self.payment_successful:
            self.payment_date = datetime.datetime.now()

        super(Order, self).save()

    def total(self):
        return sum(line.price for line in self.orderline_set.all()) + self.shipping_cost

    def total_str(self, prefix='$'):
        return "%s%.2f" % (prefix, self.total())
    total_str.short_description = "Total"

    def total_quantity(self):
        return sum(line.quantity for line in self.orderline_set.all())

    @models.permalink
    def get_absolute_url(self):
        return ('cart.views.complete', (self.hash,))

    @models.permalink
    def get_admin_url(self):
        return ('admin:cart_order_change', (self.pk,))

    def get_detail(self):
        """
        Returns extra detail as stored in the ORDER_DETAIL_MODEL setting
        """
        if not hasattr(self, '_detail_cache'):
            try:
                self._detail_cache = get_order_detail_class()._default_manager.using(self._state.db).get(order__id__exact=self.id)
                self._detail_cache.order = self
            except OrderDetailNotAvailable:
                self._detail_cache = None
        return self._detail_cache

    """
    def has_shipped(self):
        return bool(self.shipped)
    has_shipped.boolean = True
    has_shipped.short_description = 'Shipped'
    has_shipped.admin_order_field = 'shipped'

    def shipping_cost(self):
        return Decimal(str(SHIP_BASE)) + Decimal(self.shipping_base) + sum(line.shipping_cost() for line in self.orderline_set.all())

    def shipping_cost_str(self, prefix='$'):
        return u"%s%.2f" % (prefix, self.shipping_cost())

    """

class OrderLine(models.Model):
    order = models.ForeignKey(Order)

    product_content_type = models.ForeignKey(ContentType)
    product_object_id = models.PositiveIntegerField()
    product = generic.GenericForeignKey('product_content_type', 'product_object_id')

    quantity = models.IntegerField(default=1)
    # total price for the line, not per-unit
    price = models.DecimalField(max_digits=8, decimal_places=2)

    class Meta:
        pass

    def __unicode__(self):
        return unicode(self.product)
        super(OrderLine, self).save()

    def latest_payment_attempt(self):
        if self.payment_attempt_set.count():
            return self.payment_attempt_set.order_by('-creation_date')[0]
        else:
            return None

class PaymentAttempt(models.Model):
    order = models.ForeignKey(Order)
    hash = models.CharField(max_length=16, unique=True, editable=False)
    result = models.TextField(default='', blank=True)
    user_message = models.TextField(default='', blank=True)
    transaction_ref = models.CharField(max_length=32, blank=True)
    amount = models.DecimalField(max_digits=8, decimal_places=2, default=0)
    success = models.BooleanField(default=False)
    creation_date = models.DateTimeField(auto_now_add=True)

    def __unicode__(self):
        return "Payment attempt #%s on Order #%s" % (self.pk, self.order.pk)

    class Meta:
        ordering = ('-creation_date',)

def create_hash(sender, **kwargs):
    while not kwargs['instance'].hash or PaymentAttempt.objects.filter(hash=kwargs['instance'].hash).exclude(pk=kwargs['instance'].pk):
        hash = ''.join(random.choice(string.digits + string.letters) for i in xrange(8))
        kwargs['instance'].hash = hash
models.signals.pre_save.connect(create_hash, sender=PaymentAttempt)
models.signals.pre_save.connect(create_hash, sender=Order)

<commit_msg>first & last name replaced with one name field (first and last can be added via the optional order detail model)<commit_after># -*- coding: utf-8 -*-

#from django.utils.translation import ugettext_lazy as _
from django.db import models
#from django.conf import settings
#from tagging.fields import TagField
#from django.db.models import permalink

#import copy
#from decimal import Decimal
import datetime

from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
import string, random
import decimal
from utils import get_order_detail_class, OrderDetailNotAvailable

# Any items to be added to the cart must implement the following interface.
# CartProductInterface is the minimal one; it does nothing.
# DefaultCartProductInterface implements sensible defaults.

class CartProductInterface(object):
    """Minimal CartProductInterface implementation, raising NotImplementedError
    for all required methods."""
    def get_thumbnail(self, options={}):
        raise NotImplementedError()

    def get_price(self, quantity, options={}):
        raise NotImplementedError()

    @staticmethod
    def get_shipping_cost(items, options={}):
        raise NotImplementedError()

    @staticmethod
    def get_available_shipping_options(items):
        raise NotImplementedError()

    @staticmethod
    def verify_purchase(items):
        raise NotImplementedError()

class DefaultCartProductInterface(CartProductInterface):
    """CartProductInterface interface implementation, giving sensible defaults for
    all required methods."""
    def get_thumbnail(self, options={}):
        return None

    @staticmethod
    def get_shipping_cost(items, options={}):
        return 0

    @staticmethod
    def get_available_shipping_options(items):
        return None

    @staticmethod
    def verify_purchase(items):
        return True

ORDER_STATUSES = [
    ('pending', 'Pending'),
    ('confirmed', 'Confirmed'),
    ('shipped', 'Shipped'),
]

class Order(models.Model):
    hash = models.CharField(max_length=16, unique=True, editable=False)
    name = models.CharField(max_length=255)
    email = models.EmailField(default='', blank=True)
    phone = models.CharField(max_length=20, default='', blank=True)
    street_address = models.CharField(max_length=255)
    suburb = models.CharField(max_length=255, blank=True, default='')
    city = models.CharField(max_length=255)
    post_code = models.PositiveIntegerField(max_length=20)
    country = models.CharField(max_length=255)

    status = models.CharField(max_length=20, choices=ORDER_STATUSES, default='pending')
    payment_successful = models.BooleanField(default=False)
    notification_sent = models.BooleanField(default=False, editable=False)
    acknowledgement_sent = models.BooleanField(default=False, editable=False)

    creation_date = models.DateTimeField(auto_now_add=True)
    payment_date = models.DateTimeField(null=True, blank=True, help_text="Leave blank to auto-fill this field")
    completion_date = models.DateTimeField(null=True, blank=True, help_text="Leave blank to auto-fill this field")
    session_id = models.CharField(max_length=32, editable=False)

    shipping_cost = models.DecimalField(max_digits=8, decimal_places=2, default=0)

    class Meta:
        ordering = ('-creation_date',)

    def __unicode__(self):
        return "Order #%s - %s %s, %s" % (self.pk, self.first_name, self.last_name, self.total())

    def save(self):
        if (not self.completion_date) and self.status == 'shipped':
            self.completion_date = datetime.datetime.now()
        if (not self.payment_date) and self.payment_successful:
            self.payment_date = datetime.datetime.now()

        super(Order, self).save()

    def total(self):
        return sum(line.price for line in self.orderline_set.all()) + self.shipping_cost

    def total_str(self, prefix='$'):
        return "%s%.2f" % (prefix, self.total())
    total_str.short_description = "Total"

    def total_quantity(self):
        return sum(line.quantity for line in self.orderline_set.all())

    @models.permalink
    def get_absolute_url(self):
        return ('cart.views.complete', (self.hash,))

    @models.permalink
    def get_admin_url(self):
        return ('admin:cart_order_change', (self.pk,))

    def get_detail(self):
        """
        Returns extra detail as stored in the ORDER_DETAIL_MODEL setting
        """
        if not hasattr(self, '_detail_cache'):
            try:
                self._detail_cache = get_order_detail_class()._default_manager.using(self._state.db).get(order__id__exact=self.id)
                self._detail_cache.order = self
            except OrderDetailNotAvailable:
                self._detail_cache = None
        return self._detail_cache

    """
    def has_shipped(self):
        return bool(self.shipped)
    has_shipped.boolean = True
    has_shipped.short_description = 'Shipped'
    has_shipped.admin_order_field = 'shipped'

    def shipping_cost(self):
        return Decimal(str(SHIP_BASE)) + Decimal(self.shipping_base) + sum(line.shipping_cost() for line in self.orderline_set.all())

    def shipping_cost_str(self, prefix='$'):
        return u"%s%.2f" % (prefix, self.shipping_cost())

    """

class OrderLine(models.Model):
    order = models.ForeignKey(Order)

    product_content_type = models.ForeignKey(ContentType)
    product_object_id = models.PositiveIntegerField()
    product = generic.GenericForeignKey('product_content_type', 'product_object_id')

    quantity = models.IntegerField(default=1)
    # total price for the line, not per-unit
    price = models.DecimalField(max_digits=8, decimal_places=2)

    class Meta:
        pass

    def __unicode__(self):
        return unicode(self.product)
        super(OrderLine, self).save()

    def latest_payment_attempt(self):
        if self.payment_attempt_set.count():
            return self.payment_attempt_set.order_by('-creation_date')[0]
        else:
            return None

class PaymentAttempt(models.Model):
    order = models.ForeignKey(Order)
    hash = models.CharField(max_length=16, unique=True, editable=False)
    result = models.TextField(default='', blank=True)
    user_message = models.TextField(default='', blank=True)
    transaction_ref = models.CharField(max_length=32, blank=True)
    amount = models.DecimalField(max_digits=8, decimal_places=2, default=0)
    success = models.BooleanField(default=False)
    creation_date = models.DateTimeField(auto_now_add=True)

    def __unicode__(self):
        return "Payment attempt #%s on Order #%s" % (self.pk, self.order.pk)

    class Meta:
        ordering = ('-creation_date',)

def create_hash(sender, **kwargs):
    while not kwargs['instance'].hash or PaymentAttempt.objects.filter(hash=kwargs['instance'].hash).exclude(pk=kwargs['instance'].pk):
        hash = ''.join(random.choice(string.digits + string.letters) for i in xrange(8))
        kwargs['instance'].hash = hash
models.signals.pre_save.connect(create_hash, sender=PaymentAttempt)
models.signals.pre_save.connect(create_hash, sender=Order)

<|endoftext|>


<commit_before>from deepjets import learning, models, utils

n_images = 200000
n_folds = 1
test_frac = 0.5
val_frac = 0.2
sig_file = 'w_images.h5'
bkd_file = 'qcd_images.h5'
dataset_name = 'w_noshrink'
model_name = 'maxout_w_noshrink'

h5_files = utils.prepare_datasets(
    sig_file, bkd_file, dataset_name, n_sig=n_images, n_bkd=n_images, test_frac=test_frac,
    val_frac=val_frac, n_folds=n_folds, auxvars=['weights'], shuffle=True, shuffle_seed=1)
model = models.get_maxout(25**2)
learning.train_model(model, h5_files['train'], model_name)<commit_msg>added maxout.py<commit_after>from deepjets import learning, models, utils

n_images = 200000
n_folds = 1
test_frac = 0.5
val_frac = 0.2
sig_file = 'w_images.h5'
bkd_file = 'qcd_images.h5'
dataset_name = 'w_noshrink'
model_name = 'maxout_w_noshrink'

h5_files = utils.prepare_datasets(
    sig_file, bkd_file, dataset_name, n_sig=n_images, n_bkd=n_images, test_frac=test_frac,
    val_frac=val_frac, n_folds=n_folds, auxvars=['weights'], shuffle=True, shuffle_seed=1)
model = models.get_maxout(25**2)
learning.train_model(model, h5_files['train'], model_name, log_to_file=True)<|endoftext|>


<commit_before>#!/usr/bin/env python3
# settings.py
from os.path import join, dirname
from dotenv import load_dotenv
from Game_Files.database.db import Database
dotenv_path = join(dirname(__file__), '.env')
load_dotenv(dotenv_path)

# run migrations and seed
Database().migrateAndSeed()
<commit_msg>fix conflict<commit_after>#!/usr/bin/env python3
# settings.py
from os.path import join, dirname
from dotenv import load_dotenv
from Game_Files.database.db import Database
dotenv_path = join(dirname(__file__), '.env')
load_dotenv(dotenv_path)

# run migrations and seed
Database().migrateAndSeed()
<|endoftext|>


<commit_before>
#!/home/wilmer/anaconda3/bin/python

__author__ = 'wilmer'
try:
    import mkl
    have_mkl = True
    print("Running with MKL Acceleration")
except ImportError:
    have_mkl = False
    print("Running with normal backends")

from abc import ABCMeta, abstractmethod
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
import pylab
import itertools

## Class with static information about the case
class caseinfo:
    isoX = 0.0
    isoY = 0.0
    R = 1.0
    ## Number of beamlets in the fan
    N = 64
    interleaf = 0.6
    ## Source to axis distance calibration in cms
    SAD = 80
    ## Original fan
    genFan2D = None
    def __init__(self, x = 0.0, y = 0.0, radio = 1.0):
        self.isoX = x
        self.isoY = y
        self.R = radio
        self.genFan2D = np.transpose(np.matrix([[self.interleaf * (i - self.N/2 + 1/2), self.SAD] for i in range(0, self.N)]))

## Class that uses a data pair and implements some geographical operations. Depth of the voxel given beam.
class geoloc:
    def __init__(self, x = 0.0, y = 0.0):
        self.x = x
        self.y = y
        self.depth = None
    ## This function calculates the distance from my geographical location to the center of a beamlet
    def distToBeamC(self, xBeamC, yBeamC , zBeamC ):
        d = np.sqrt(np.sum((self.x - xBeamC )**2 + (self.y - yBeamC )**2))
        return(d)
    ## Function to calculate distance from this point to isocenter
    def distToIsoC(self):
        d = np.sqrt(np.sum((self.x - thiscase.isoX)**2 + (self.y - thiscase.isoY)**2))
        return(d)

    ## This function finds whether a point lies INSIDE the line SEGMENT between the beamlet and the voxel or not.
    def isinterior(self, xinterp, xBeamC):
        ininterior = False
        if (np.min(xBeamC, self.x) <= xinterp and xinterp <= np.max(xBeamC, self.x)):
            ininterior = True
        return(ininterior)

    ## Find the depth of this voxel inside the body
    def depthBeamC(self, xBeamC, yBeamC, zBeamC, dBeamlettoIso):
        ## To understand the methodology look at http://mathworld.wolfram.com/Circle-LineIntersection.html
        x2 = xBeamC
        y2 = yBeamC
        x1 = self.x
        y1 = self.y
        dx = x2 - x1
        dy = y2 - y1
        dr = np.sqrt(dx**2 + dy**2)
        D = x1 * y2 - x2 * y1
        ## There are two point of intersection
        xinterp = (D * dy + np.sign(dy) * dx * np.sqrt(thiscase.R**2 * dr**2 - D**2))/(dr**2)
        xinterm = (D * dy - np.sign(dy) * dx * np.sqrt(thiscase.R**2 * dr**2 - D**2))/(dr**2)
        yinterp = (-D * dx + np.abs(dy) * np.sqrt(thiscase.R ** 2 * dr ** 2 - D ** 2)) / (dr ** 2)
        yinterm = (-D * dx - np.abs(dy) * np.sqrt(thiscase.R ** 2 * dr ** 2 - D ** 2)) / (dr ** 2)
        ## Check which one of the intersection points lies in the segment
        if (self.isinterior(xinterp, xBeamC)):
            intX = xinterp
            intY = yinterp
        else:
            intX = xinterm
            intY = yinterm
        ## Check that indeed you did everything right
        assert(np.min(xBeamC, self.x) <= intX and intX <= np.max(xBeamC, self.x))
        ## Use the point of intersection to calculate the depth of the voxel
        self.depth = np.sqrt((intX - self.x)**2 + (intY - self.y)**2)

## Abstract class that implements a volume of interest with common location and radius. Parent of OAR and TARGET
class VOI:
    __metaclass__ = ABCMeta
    def __init__(self, x = 0.0, y = 0.0, r = 0.0):
        ## X location of center
        self.xcenter = x
        ## Y location of ceter
        self.ycenter = y
        ## Radius of the Volume of Interest. All of them are circumferences
        self.radius = r
        self.isTarget = None
        self.isinside = self.isContained()
    ## This method finds whether the attribute is viable, given its center and radius and given the center and radius
    ## of the original body that contains it
    def isContained(self):
        isv = True
        ## Find radius from center of VOI to center of structure
        distcenter = np.sqrt((self.xcenter - thiscase.isoX)**2 + (self.ycenter - thiscase.isoY)**2)
        if distcenter + self.radius > thiscase.R:
            isv = False
        return (isv)
    ## This method takes a location in space and returns whether this location exists in this VOI or not
    def isInThisVOI(self, x, y):
        isinit = False
        distcenter = np.sqrt((self.xcenter - x) ** 2 + (self.ycenter - y) ** 2)
        if distcenter <= self.radius:
            isinit = True
        return(isinit)d
    # Abstract method to be implemented by classes deriving from here
    @abstractmethod
    def printVOI(self):
        pass

class OAR(VOI):
    numOARS = 0.0
    def __init__(self, x = 0.0, y = 0.0, r = 0.0):
        ## Boolean. Is this a target structure?
        self.isTarget = True
        super(OAR, self).__init__(x, y, r)
        self.numOARS = self.numOARS + 1

    def printVOI(self):
        print('OAR with center (', self.xcenter, ', ', self.ycenter, '); and radius ', self.radius)

class TARGET(VOI):
    numTARGETS = 0.0
    def __init__(self, x = 0.0, y = 0.0, r = 0.0):
        ## Boolean. Is this a target structure?
        self.isTarget = False
        super(TARGET, self).__init__(x, y, r)
        self.numTARGETS = self.numTARGETS + 1
    def printVOI(self):
        print('Target with center (', self.xcenter, ', ', self.ycenter, '); and radius ', self.radius)

## The next class defines a control point; in particular, the location of all beamlets
class ControlPoint:
    def __init__(self, ctrlAngle):
        angleDegs = ctrlAngle
        angleRads = (2 * np.pi * angleDegs)/360
        rotMat = np.matrix([[np.cos(angleRads), -np.sin(angleRads)], [np.sin(angleRads), np.cos(angleRads)]])
        thisFan = rotMat * thiscase.genFan2D
        print(thisFan, thisFan.shape)

#class voxel:

## This function takes a list of numeric values as arguments and produces the list of D matrices
## The box has isocenter on position thiscase.x
# Inputs:
# anglelist = [list of numeric]. These are the control points
# numhozv = Number of horizontal voxel divisions
# numverv = Number of vertical voxel divisions
# xgeoloc = X Geographic location of upper-right side of box
# ygeoloc = Y Geographic location of upper-right side of box
# radius  = Radius of the body
# OARList = List of OAR centers and radiuses
# TARGETList = List of Target centers and radiuses
# Outputs:
# listofD = List of D matrix objects
# upper right corner is (X,Y), lower left corner is (-X, -Y)
def createDosetoPoints(anglelist, numhozv, numverv, xgeoloc, ygeoloc, radius):
    ## Generate 360 control points
    cps = [ControlPoint(i) for i in anglelist]
    ## Create voxels
    voxelhoz = np.arange(-xgeoloc, xgeoloc, 2 * xgeoloc/numhozv) + xgeoloc/numhozv
    voxelvec = np.arange(-ygeoloc, ygeoloc, 2 * ygeoloc/numverv) + ygeoloc/numverv
    voxelcenters = itertools.product(voxelhoz, voxelvec)
    return()

## Implementation part that should be separated later
def plotstructure(OARlist, TARGETlist, xgeo, ygeo):
    ## This function plots the case to make sure that everything is understood
    numOARS = len(OARlist)
    numTARGETS = len(TARGETlist)
    # Plot the outside circle
    circlemain = plt.Circle((thiscase.isoX, thiscase.isoY), thiscase.R, color = 'blue', fill = False)
    fig = plt.gcf()
    fig.gca().add_artist(circlemain)
    pylab.xlim([-xgeo, xgeo])
    pylab.ylim([-ygeo, ygeo])
    for i in range(0, numOARS):
        circle = plt.Circle((OARlist[i].xcenter, OARlist[i].ycenter), OARlist[i].radius, color = 'g', fill = False)
        fig.gca().add_artist(circle)
    for i in range(0, numTARGETS):
        circle = plt.Circle((TARGETlist[i].xcenter, TARGETlist[i].ycenter), TARGETlist[i].radius, color = 'r', fill = False)
        fig.gca().add_artist(circle)
    fig.suptitle('Case Plot')
    fig.savefig('plotcase.png')

bodyradius = 7.0
thiscase = caseinfo(0.0, 0.0, bodyradius)
## Create 3 OARs around the body
OARlist = []
OARlist.append(OAR(5.0, 0.0, 1.0))
OARlist.append(OAR(3.0, 2.0, 2.5))
OARlist.append(OAR(-3.0, 2.0, 1.3))
TARGETlist = []
TARGETlist.append(TARGET(0.0, 0.0, 2.0))
TARGETlist.append(TARGET(-4.0, -4.0, 1.2))

## Initialize an instance. This is not necessary but it is good practice.
xgeoloc = bodyradius
ygeoloc = bodyradius
plotstructure(OARlist, TARGETlist, xgeoloc, ygeoloc)
numhozv = 20
numverv = 20
xgeoloc = bodyradius
ygeoloc = bodyradius
radius = bodyradius
anglelist = [i * 360 / 51 for i in range(0, 51)]

createDosetoPoints(anglelist, numhozv, numverv, xgeoloc, ygeoloc, radius)<commit_msg>Added counters for all of the structures, counters for VOIs, TARGETs and OARs<commit_after>
#!/home/wilmer/anaconda3/bin/python

__author__ = 'wilmer'
try:
    import mkl
    have_mkl = True
    print("Running with MKL Acceleration")
except ImportError:
    have_mkl = False
    print("Running with normal backends")

from abc import ABCMeta, abstractmethod
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
import pylab
import itertools

## Class with static information about the case
class caseinfo:
    isoX = 0.0
    isoY = 0.0
    R = 1.0
    ## Number of beamlets in the fan
    N = 64
    interleaf = 0.6
    ## Source to axis distance calibration in cms
    SAD = 80
    ## Original fan
    genFan2D = None
    def __init__(self, x = 0.0, y = 0.0, radio = 1.0):
        self.isoX = x
        self.isoY = y
        self.R = radio
        self.genFan2D = np.transpose(np.matrix([[self.interleaf * (i - self.N/2 + 1/2), self.SAD] for i in range(0, self.N)]))

## Class that uses a data pair and implements some geographical operations. Depth of the voxel given beam.
class geoloc:
    def __init__(self, x = 0.0, y = 0.0):
        self.x = x
        self.y = y
        self.depth = None
    ## This function calculates the distance from my geographical location to the center of a beamlet
    def distToBeamC(self, xBeamC, yBeamC , zBeamC ):
        d = np.sqrt(np.sum((self.x - xBeamC )**2 + (self.y - yBeamC )**2))
        return(d)
    ## Function to calculate distance from this point to isocenter
    def distToIsoC(self):
        d = np.sqrt(np.sum((self.x - thiscase.isoX)**2 + (self.y - thiscase.isoY)**2))
        return(d)

    ## This function finds whether a point lies INSIDE the line SEGMENT between the beamlet and the voxel or not.
    def isinterior(self, xinterp, xBeamC):
        ininterior = False
        if (np.min(xBeamC, self.x) <= xinterp and xinterp <= np.max(xBeamC, self.x)):
            ininterior = True
        return(ininterior)

    ## Find the depth of this voxel inside the body
    def depthBeamC(self, xBeamC, yBeamC, zBeamC, dBeamlettoIso):
        ## To understand the methodology look at http://mathworld.wolfram.com/Circle-LineIntersection.html
        x2 = xBeamC
        y2 = yBeamC
        x1 = self.x
        y1 = self.y
        dx = x2 - x1
        dy = y2 - y1
        dr = np.sqrt(dx**2 + dy**2)
        D = x1 * y2 - x2 * y1
        ## There are two point of intersection
        xinterp = (D * dy + np.sign(dy) * dx * np.sqrt(thiscase.R**2 * dr**2 - D**2))/(dr**2)
        xinterm = (D * dy - np.sign(dy) * dx * np.sqrt(thiscase.R**2 * dr**2 - D**2))/(dr**2)
        yinterp = (-D * dx + np.abs(dy) * np.sqrt(thiscase.R ** 2 * dr ** 2 - D ** 2)) / (dr ** 2)
        yinterm = (-D * dx - np.abs(dy) * np.sqrt(thiscase.R ** 2 * dr ** 2 - D ** 2)) / (dr ** 2)
        ## Check which one of the intersection points lies in the segment
        if (self.isinterior(xinterp, xBeamC)):
            intX = xinterp
            intY = yinterp
        else:
            intX = xinterm
            intY = yinterm
        ## Check that indeed you did everything right
        assert(np.min(xBeamC, self.x) <= intX and intX <= np.max(xBeamC, self.x))
        ## Use the point of intersection to calculate the depth of the voxel
        self.depth = np.sqrt((intX - self.x)**2 + (intY - self.y)**2)

## Abstract class that implements a volume of interest with common location and radius. Parent of OAR and TARGET
class VOI:
    numVOIs = 0
    __metaclass__ = ABCMeta
    def __init__(self, x = 0.0, y = 0.0, r = 0.0):
        ## X location of center
        self.xcenter = x
        ## Y location of ceter
        self.ycenter = y
        ## Radius of the Volume of Interest. All of them are circumferences
        self.radius = r
        self.isTarget = None
        self.isinside = self.isContained()
        self.VOIID = VOI.numVOIs
        VOI.numVOIs = VOI.numVOIs + 1
    ## This method finds whether the attribute is viable, given its center and radius and given the center and radius
    ## of the original body that contains it
    def isContained(self):
        isv = True
        ## Find radius from center of VOI to center of structure
        distcenter = np.sqrt((self.xcenter - thiscase.isoX)**2 + (self.ycenter - thiscase.isoY)**2)
        if distcenter + self.radius > thiscase.R:
            isv = False
        return (isv)
    ## This method takes a location in space and returns whether this location exists in this VOI or not
    def isInThisVOI(self, x, y):
        isinit = False
        distcenter = np.sqrt((self.xcenter - x) ** 2 + (self.ycenter - y) ** 2)
        if distcenter <= self.radius:
            isinit = True
        return(isinit)
    # Abstract method to be implemented by classes deriving from here
    @abstractmethod
    def printVOI(self):
        pass

class OAR(VOI):
    numOARS = 0
    def __init__(self, x = 0.0, y = 0.0, r = 0.0):
        ## Boolean. Is this a target structure?
        self.isTarget = True
        super(OAR, self).__init__(x, y, r)
        ## Assign an ID to each of the different OARs
        self.OARID = OAR.numOARS
        OAR.numOARS = OAR.numOARS + 1

    def printVOI(self):
        print('OAR with center (', self.xcenter, ', ', self.ycenter, '); and radius ', self.radius)

class TARGET(VOI):
    numTARGETS = 0
    def __init__(self, x = 0.0, y = 0.0, r = 0.0):
        ## Boolean. Is this a target structure?
        self.isTarget = False
        super(TARGET, self).__init__(x, y, r)
        ## Assign an ID to each of the different targets
        self.TARGETID = TARGET.numTARGETS
        TARGET.numTARGETS = TARGET.numTARGETS + 1
    def printVOI(self):
        print('Target with center (', self.xcenter, ', ', self.ycenter, '); and radius ', self.radius)

## The next class defines a control point; in particular, the location of all beamlets
class ControlPoint:
    def __init__(self, ctrlAngle):
        angleDegs = ctrlAngle
        angleRads = (2 * np.pi * angleDegs)/360
        rotMat = np.matrix([[np.cos(angleRads), -np.sin(angleRads)], [np.sin(angleRads), np.cos(angleRads)]])
        thisFan = rotMat * thiscase.genFan2D

class voxel:
    def __init__(self, vc, OARS, TARGETS):
        self.x = vc[0]
        self.y = vc[1]
        self.belongsToVOI = False
        self.inStructureID = None
        ## Run this code for all OARs and TARGETs, preference to targets
        for voi in OARS + TARGETS:
            if voi.isInThisVOI(self.x, self.y):
                self.belongsToVOI = True
                self.inStructureID = voi.VOIID
## This function takes a list of numeric values as arguments and produces the list of D matrices
## The box has isocenter on position thiscase.x
# Inputs:
# anglelist = [list of numeric]. These are the control points
# numhozv = Number of horizontal voxel divisions
# numverv = Number of vertical voxel divisions
# xgeoloc = X Geographic location of upper-right side of box
# ygeoloc = Y Geographic location of upper-right side of box
# radius  = Radius of the body
# OARList = List of OAR centers and radiuses
# TARGETList = List of Target centers and radiuses
# Outputs:
# listofD = List of D matrix objects
# upper right corner is (X,Y), lower left corner is (-X, -Y)
def createDosetoPoints(anglelist, numhozv, numverv, xgeoloc, ygeoloc, radius, OARS, TARGETS):
    ## Generate 360 control points
    cps = [ControlPoint(i) for i in anglelist]
    ## Create voxels
    voxelhoz = np.arange(-xgeoloc, xgeoloc, 2 * xgeoloc/numhozv) + xgeoloc/numhozv
    voxelvec = np.arange(-ygeoloc, ygeoloc, 2 * ygeoloc/numverv) + ygeoloc/numverv
    ## Create cartesian product to find voxel centers
    voxelcenters = itertools.product(voxelhoz, voxelvec)
    ## Limit the list only to those voxels that are included in the body and assign a organ to them
    allvoxels = [voxel(voxelcenter, OARS, TARGETS) for voxelcenter in voxelcenters]
    ## Filter only those voxels that belong in any VOI
    voxels = [vxinvoi for vxinvoi in allvoxels if vxinvoi.belongsToVOI]
    [print(i.inStructureID) for i in voxels]
    allvoxels = None # Free some memory
    return(1)

## Implementation part that should be separated later
def plotstructure(OARlist, TARGETlist, xgeo, ygeo):
    ## This function plots the case to make sure that everything is understood
    numOARS = len(OARlist)
    numTARGETS = len(TARGETlist)
    # Plot the outside circle
    circlemain = plt.Circle((thiscase.isoX, thiscase.isoY), thiscase.R, color = 'blue', fill = False)
    fig = plt.gcf()
    fig.gca().add_artist(circlemain)
    pylab.xlim([-xgeo, xgeo])
    pylab.ylim([-ygeo, ygeo])
    for i in range(0, numOARS):
        circle = plt.Circle((OARlist[i].xcenter, OARlist[i].ycenter), OARlist[i].radius, color = 'g', fill = False)
        fig.gca().add_artist(circle)
    for i in range(0, numTARGETS):
        circle = plt.Circle((TARGETlist[i].xcenter, TARGETlist[i].ycenter), TARGETlist[i].radius, color = 'r', fill = False)
        fig.gca().add_artist(circle)
    fig.suptitle('Case Plot')
    fig.savefig('plotcase.png')

bodyradius = 7.0
thiscase = caseinfo(0.0, 0.0, bodyradius)
## Create 3 OARs around the body
OARlist = []
OARlist.append(OAR(5.0, 0.0, 1.0))
OARlist.append(OAR(3.0, 2.0, 2.5))
OARlist.append(OAR(-3.0, 2.0, 1.3))
TARGETlist = []
TARGETlist.append(TARGET(0.0, 0.0, 2.0))
TARGETlist.append(TARGET(-4.0, -4.0, 1.2))

## Initialize an instance. This is not necessary but it is good practice.
xgeoloc = bodyradius
ygeoloc = bodyradius
plotstructure(OARlist, TARGETlist, xgeoloc, ygeoloc)
numhozv = 20
numverv = 20
xgeoloc = bodyradius
ygeoloc = bodyradius
radius = bodyradius
anglelist = [i * 360 / 51 for i in range(0, 51)]

createDosetoPoints(anglelist, numhozv, numverv, xgeoloc, ygeoloc, radius, OARlist, TARGETlist)<|endoftext|>


<commit_before># Copyright 2016 Adobe. All rights reserved.

# Methods:

# Parse args. If glyphlist is from file, read in entire file as single string,
# and remove all white space, then parse out glyph-names and GID's.

# For each font name:
#   Use fontTools library to open font and extract CFF table.
#   If error, skip font and report error.
#   Filter specified glyph list, if any, with list of glyphs in the font.
#   Open font plist file, if any. If not, create empty font plist.
#   Build alignment zone string
#   For identifier in glyph-list:
#     Get T2 charstring for glyph from parent font CFF table. If not present,
#       report and skip.
#     Get new alignment zone string if FDarray index (which font dict is used)
#       has changed.
#     Convert to bez
#     Build autohint point list string; this is used to tell if glyph has been
#       changed since the last time it was hinted.
#     If requested, check against plist dict, and skip if glyph is already
#       hinted or is manually hinted.
#     Call autohint library on bez string.
#     If change to the point list is permitted and happened, rebuild.
#     Autohint point list string.
#     Convert bez string to T2 charstring, and update parent font CFF.
#     Add glyph hint entry to plist file
#  Save font plist file.

from __future__ import print_function, absolute_import

import logging
import os
import re
import shutil
import time

from fontTools.ttLib import TTFont, getTableClass

from .otfFont import CFFFontData
from .ufoFont import UFOFontData, kAutohintName, kCheckOutlineName

from . import get_font_format, hint_bez_glyph, hint_compatible_bez_glyphs

log = logging.getLogger(__name__)

class ACOptions(object):
    def __init__(self):
        self.inputPaths = []
        self.outputPaths = []
        self.reference_font = None
        self.glyphList = []
        self.nameAliases = {}
        self.excludeGlyphList = False
        self.usePlistFile = False
        self.hintAll = False
        self.rehint = False
        self.allowChanges = False
        self.noFlex = False
        self.noHintSub = False
        self.allow_no_blues = False
        self.hCounterGlyphs = []
        self.vCounterGlyphs = []
        self.logOnly = False
        self.printDefaultFDDict = False
        self.printFDDictList = False
        self.allowDecimalCoords = False
        self.writeToDefaultLayer = False
        self.baseMaster = {}
        self.font_format = None

class ACFontError(Exception):
    pass

class ACHintError(Exception):
    pass

def getGlyphID(glyphTag, fontGlyphList):
    if glyphTag in fontGlyphList:
        return fontGlyphList.index(glyphTag)

    return None

def getGlyphNames(glyphTag, fontGlyphList, fontFileName):
    glyphNameList = []
    rangeList = glyphTag.split("-")
    prevGID = getGlyphID(rangeList[0], fontGlyphList)
    if prevGID is None:
        if len(rangeList) > 1:
            log.warning("glyph ID <%s> in range %s from glyph selection "
                        "list option is not in font. <%s>.",
                        rangeList[0], glyphTag, fontFileName)
        else:
            log.warning("glyph ID <%s> from glyph selection list option "
                        "is not in font. <%s>.", rangeList[0], fontFileName)
        return None
    glyphNameList.append(fontGlyphList[prevGID])

    for glyphTag2 in rangeList[1:]:
        gid = getGlyphID(glyphTag2, fontGlyphList)
        if gid is None:
            log.warning("glyph ID <%s> in range %s from glyph selection "
                        "list option is not in font. <%s>.",
                        glyphTag2, glyphTag, fontFileName)
            return None
        for i in range(prevGID + 1, gid + 1):
            glyphNameList.append(fontGlyphList[i])
        prevGID = gid

    return glyphNameList

def filterGlyphList(options, fontGlyphList, fontFileName):
    # Return the list of glyphs which are in the intersection of the argument
    # list and the glyphs in the font.
    # Complain about glyphs in the argument list which are not in the font.
    if not options.glyphList:
        glyphList = fontGlyphList
    else:
        # expand ranges:
        glyphList = []
        for glyphTag in options.glyphList:
            glyphNames = getGlyphNames(glyphTag, fontGlyphList, fontFileName)
            if glyphNames is not None:
                glyphList.extend(glyphNames)
        if options.excludeGlyphList:
            newList = filter(lambda name: name not in glyphList, fontGlyphList)
            glyphList = newList
    return glyphList

fontInfoKeywordList = [
    'FontName',  # string
    'OrigEmSqUnits',
    'LanguageGroup',
    'DominantV',  # array
    'DominantH',  # array
    'FlexOK',  # string
    'BlueFuzz',
    'VCounterChars',  # counter
    'HCounterChars',  # counter
    'BaselineYCoord',
    'BaselineOvershoot',
    'CapHeight',
    'CapOvershoot',
    'LcHeight',
    'LcOvershoot',
    'AscenderHeight',
    'AscenderOvershoot',
    'FigHeight',
    'FigOvershoot',
    'Height5',
    'Height5Overshoot',
    'Height6',
    'Height6Overshoot',
    'DescenderOvershoot',
    'DescenderHeight',
    'SuperiorOvershoot',
    'SuperiorBaseline',
    'OrdinalOvershoot',
    'OrdinalBaseline',
    'Baseline5Overshoot',
    'Baseline5',
    'Baseline6Overshoot',
    'Baseline6',
]

integerPattern = """ -?\d+"""
arrayPattern = """ \[[ ,0-9]+\]"""
stringPattern = """ \S+"""
counterPattern = """ \([\S ]+\)"""

def printFontInfo(fontInfoString):
    for item in fontInfoKeywordList:
        if item in ['FontName', 'FlexOK']:
            matchingExp = item + stringPattern
        elif item in ['VCounterChars', 'HCounterChars']:
            matchingExp = item + counterPattern
        elif item in ['DominantV', 'DominantH']:
            matchingExp = item + arrayPattern
        else:
            matchingExp = item + integerPattern

        try:
            print('\t%s' % re.search(matchingExp, fontInfoString).group())
        except Exception:
            pass

def openFile(path, outFilePath, options):
    font_format = get_font_format(path)
    if font_format is None:
        raise ACFontError("{} is not a supported font format".format(path))

    if font_format == "UFO":
        font = openUFOFile(path, outFilePath, options)
    elif font_format in ("OTF", "CFF"):
        font = openOpenTypeFile(path, outFilePath, font_format, options)
    else:
        raise NotImplementedError("%s format is not supported yet, sorry." %
                                  font_format)

    return font

def openUFOFile(path, outFilePath, options):
    # If user has specified a path other than the source font path,
    # then copy the entire UFO font, and operate on the copy.
    if (outFilePath is not None) and (
       os.path.abspath(path) != os.path.abspath(outFilePath)):
        log.info("Copying from source UFO font to output UFO font "
                 "before processing...")
        if os.path.exists(outFilePath):
            shutil.rmtree(outFilePath)
        shutil.copytree(path, outFilePath)
        path = outFilePath
    # We always use the hash map to skip glyphs that have been previously
    # processed, unless the user has report only, not make changes.
    useHashMap = not options.logOnly
    font = UFOFontData(path, useHashMap, options.allowDecimalCoords,
                       kAutohintName)
    font.useProcessedLayer = True
    if options.writeToDefaultLayer:
        font.setWriteToDefault()
    # Programs in this list must be run before autohint,
    # if the outlines have been edited.
    font.requiredHistory.append(kCheckOutlineName)
    return font

def openOpenTypeFile(path, outFilePath, font_format, options):
    # If input font is CFF, build a dummy ttFont in memory.
    if font_format == "OTF":  # it is an OTF font, can process file directly
        ttFont = TTFont(path)
        if "CFF " not in ttFont:
            raise ACFontError("Font is not a CFF font <%s>." % path)
    elif font_format == "CFF":
        # now package the CFF font as an OTF font.
        with open(path, "rb") as ff:
            data = ff.read()

        ttFont = TTFont()
        cffClass = getTableClass('CFF ')
        ttFont['CFF '] = cffClass('CFF ')
        ttFont['CFF '].decompile(data, ttFont)
    else:
        raise ACFontError("Font file must be CFF or OTF file: %s." % path)

    fontData = CFFFontData(ttFont, path, outFilePath,
                           options.allowDecimalCoords, font_format)
    return fontData

def cmpFDDictEntries(entry1, entry2):
    # entry = [glyphName, [fdIndex, glyphListIndex] ]
    if entry1[1][1] > entry2[1][1]:
        return 1
    elif entry1[1][1] < entry2[1][1]:
        return -1
    else:
        return 0

def hintFiles(options):
    if options.reference_font:
        hintFile(options, options.reference_font, None, reference_master=True)
    for i, path in enumerate(options.inputPaths):
        outpath = None
        if options.outputPaths is not None and i < len(options.outputPaths):
            outpath = options.outputPaths[i]
        hintFile(options, path, outpath, reference_master=False)

def hintFile(options, path, outpath, reference_master):
    nameAliases = options.nameAliases

    fontFileName = os.path.basename(path)
    log.info("Hinting font %s. Start time: %s.", path, time.asctime())

    fontData = openFile(path, outpath, options)

    # filter specified list, if any, with font list.
    fontGlyphList = fontData.getGlyphList()
    glyphList = filterGlyphList(options, fontGlyphList, fontFileName)
    if not glyphList:
        raise ACFontError("Selected glyph list is empty for font <%s>." %
                          fontFileName)

    fontInfo = ""

    psName = fontData.getPSName()

    # Check counter glyphs, if any.
    if options.hCounterGlyphs or options.vCounterGlyphs:
        missingList = filter(lambda name: name not in fontGlyphList,
                             options.hCounterGlyphs + options.vCounterGlyphs)
        if missingList:
            log.error("H/VCounterChars glyph named in fontinfo is "
                      "not in font: %s", missingList)

    # Build alignment zone string
    if options.printDefaultFDDict:
        print("Showing default FDDict Values:")
        fdDict = fontData.getFontInfo(psName, path,
                                      options.allow_no_blues,
                                      options.noFlex,
                                      options.vCounterGlyphs,
                                      options.hCounterGlyphs)
        printFontInfo(str(fdDict))
        fontData.close()
        return

    fdGlyphDict, fontDictList = fontData.getfdInfo(psName, path,
                                                   options.allow_no_blues,
                                                   options.noFlex,
                                                   options.vCounterGlyphs,
                                                   options.hCounterGlyphs,
                                                   glyphList)

    if options.printFDDictList:
        # Print the user defined FontDicts, and exit.
        if fdGlyphDict:
            print("Showing user-defined FontDict Values:")
            for fi in enumerate(fontDictList):
                fontDict = fontDictList[fi]
                print(fontDict.DictName)
                printFontInfo(str(fontDict))
                gnameList = []
                itemList = fdGlyphDict.items()
                itemList.sort(cmpFDDictEntries)
                for gName, entry in itemList:
                    if entry[0] == fi:
                        gnameList.append(gName)
                print("%d glyphs:" % len(gnameList))
                if len(gnameList) > 0:
                    gTxt = " ".join(gnameList)
                else:
                    gTxt = "None"
                print(gTxt)
        else:
            print("There are no user-defined FontDict Values.")
        fontData.close()
        return

    if fdGlyphDict is None:
        fdDict = fontDictList[0]
        fontInfo = fdDict.getFontInfo()
    else:
        log.info("Using alternate FDDict global values from fontinfo "
                 "file for some glyphs.")

    # Get charstring for identifier in glyph-list
    isCID = fontData.isCID()
    lastFDIndex = None
    anyGlyphChanged = False
    if isCID:
        options.noFlex = True

    seenGlyphCount = 0
    processedGlyphCount = 0
    for name in glyphList:
        seenGlyphCount += 1

        # Convert to bez format
        bezString, width = fontData.convertToBez(name, options.hintAll)
        processedGlyphCount += 1
        if bezString is None:
            continue

        if "mt" not in bezString:
            # skip empty glyphs.
            continue
        # get new fontinfo string if FDarray index has changed,
        # as each FontDict has different alignment zones.
        gid = fontData.getGlyphID(name)
        if isCID:
            fdIndex = fontData.getfdIndex(gid)
            if not fdIndex == lastFDIndex:
                lastFDIndex = fdIndex
                fdDict = fontData.getFontInfo(psName, path,
                                              options.allow_no_blues,
                                              options.noFlex,
                                              options.vCounterGlyphs,
                                              options.hCounterGlyphs,
                                              fdIndex)
                fontInfo = fdDict.getFontInfo()
        else:
            if fdGlyphDict is not None:
                try:
                    fdIndex = fdGlyphDict[name][0]
                except KeyError:
                    # use default dict.
                    fdIndex = 0
                if lastFDIndex != fdIndex:
                    lastFDIndex = fdIndex
                    fdDict = fontDictList[fdIndex]
                    fontInfo = fdDict.getFontInfo()

        # Build autohint point list identifier
        oldBezString = ""
        oldHintBezString = ""

        if fdGlyphDict:
            log.info("%s: Begin hinting (using fdDict %s).",
                     nameAliases.get(name, name), fdDict.DictName)
        else:
            log.info("%s: Begin hinting.", nameAliases.get(name, name))

        # Call auto-hint library on bez string.
        if oldBezString != "" and oldBezString == bezString:
            newBezString = oldHintBezString
        else:
            if reference_master or not options.reference_font:
                newBezString = hint_bez_glyph(fontInfo, bezString,
                                              options.allowChanges,
                                              not options.noHintSub,
                                              options.allowDecimalCoords)
                options.baseMaster[name] = newBezString
            else:
                baseFontFileName = os.path.basename(options.reference_font)
                masters = [baseFontFileName, fontFileName]
                glyphs = [options.baseMaster[name], bezString]
                newBezString = hint_compatible_bez_glyphs(fontInfo, glyphs,
                                                          masters)
                newBezString = newBezString[1]  # FIXME

        if not newBezString:
            raise ACHintError(
                "%s Error - failure in processing outline data." %
                nameAliases.get(name, name))

        if not (("ry" in newBezString[:200]) or ("rb" in newBezString[:200]) or
           ("rm" in newBezString[:200]) or ("rv" in newBezString[:200])):
            log.info("No hints added!")

        if options.logOnly:
            continue

        # Convert bez to charstring, and update CFF.
        anyGlyphChanged = True
        fontData.updateFromBez(newBezString, name, width)

    if not options.logOnly:
        if anyGlyphChanged:
            log.info("Saving font file with new hints..." + time.asctime())
            fontData.saveChanges()
        else:
            fontData.close()
            log.info("No glyphs were hinted.")
    if processedGlyphCount != seenGlyphCount:
        log.info("Skipped %s of %s glyphs.",
                 seenGlyphCount - processedGlyphCount, seenGlyphCount)
    log.info("Done with font %s. End time: %s.", path, time.asctime())
<commit_msg>Fix --print-list-fddict option<commit_after># Copyright 2016 Adobe. All rights reserved.

# Methods:

# Parse args. If glyphlist is from file, read in entire file as single string,
# and remove all white space, then parse out glyph-names and GID's.

# For each font name:
#   Use fontTools library to open font and extract CFF table.
#   If error, skip font and report error.
#   Filter specified glyph list, if any, with list of glyphs in the font.
#   Open font plist file, if any. If not, create empty font plist.
#   Build alignment zone string
#   For identifier in glyph-list:
#     Get T2 charstring for glyph from parent font CFF table. If not present,
#       report and skip.
#     Get new alignment zone string if FDarray index (which font dict is used)
#       has changed.
#     Convert to bez
#     Build autohint point list string; this is used to tell if glyph has been
#       changed since the last time it was hinted.
#     If requested, check against plist dict, and skip if glyph is already
#       hinted or is manually hinted.
#     Call autohint library on bez string.
#     If change to the point list is permitted and happened, rebuild.
#     Autohint point list string.
#     Convert bez string to T2 charstring, and update parent font CFF.
#     Add glyph hint entry to plist file
#  Save font plist file.

from __future__ import print_function, absolute_import

import logging
import os
import re
import shutil
import time

from fontTools.ttLib import TTFont, getTableClass

from .otfFont import CFFFontData
from .ufoFont import UFOFontData, kAutohintName, kCheckOutlineName

from . import get_font_format, hint_bez_glyph, hint_compatible_bez_glyphs

log = logging.getLogger(__name__)

class ACOptions(object):
    def __init__(self):
        self.inputPaths = []
        self.outputPaths = []
        self.reference_font = None
        self.glyphList = []
        self.nameAliases = {}
        self.excludeGlyphList = False
        self.usePlistFile = False
        self.hintAll = False
        self.rehint = False
        self.allowChanges = False
        self.noFlex = False
        self.noHintSub = False
        self.allow_no_blues = False
        self.hCounterGlyphs = []
        self.vCounterGlyphs = []
        self.logOnly = False
        self.printDefaultFDDict = False
        self.printFDDictList = False
        self.allowDecimalCoords = False
        self.writeToDefaultLayer = False
        self.baseMaster = {}
        self.font_format = None

class ACFontError(Exception):
    pass

class ACHintError(Exception):
    pass

def getGlyphID(glyphTag, fontGlyphList):
    if glyphTag in fontGlyphList:
        return fontGlyphList.index(glyphTag)

    return None

def getGlyphNames(glyphTag, fontGlyphList, fontFileName):
    glyphNameList = []
    rangeList = glyphTag.split("-")
    prevGID = getGlyphID(rangeList[0], fontGlyphList)
    if prevGID is None:
        if len(rangeList) > 1:
            log.warning("glyph ID <%s> in range %s from glyph selection "
                        "list option is not in font. <%s>.",
                        rangeList[0], glyphTag, fontFileName)
        else:
            log.warning("glyph ID <%s> from glyph selection list option "
                        "is not in font. <%s>.", rangeList[0], fontFileName)
        return None
    glyphNameList.append(fontGlyphList[prevGID])

    for glyphTag2 in rangeList[1:]:
        gid = getGlyphID(glyphTag2, fontGlyphList)
        if gid is None:
            log.warning("glyph ID <%s> in range %s from glyph selection "
                        "list option is not in font. <%s>.",
                        glyphTag2, glyphTag, fontFileName)
            return None
        for i in range(prevGID + 1, gid + 1):
            glyphNameList.append(fontGlyphList[i])
        prevGID = gid

    return glyphNameList

def filterGlyphList(options, fontGlyphList, fontFileName):
    # Return the list of glyphs which are in the intersection of the argument
    # list and the glyphs in the font.
    # Complain about glyphs in the argument list which are not in the font.
    if not options.glyphList:
        glyphList = fontGlyphList
    else:
        # expand ranges:
        glyphList = []
        for glyphTag in options.glyphList:
            glyphNames = getGlyphNames(glyphTag, fontGlyphList, fontFileName)
            if glyphNames is not None:
                glyphList.extend(glyphNames)
        if options.excludeGlyphList:
            newList = filter(lambda name: name not in glyphList, fontGlyphList)
            glyphList = newList
    return glyphList

fontInfoKeywordList = [
    'FontName',  # string
    'OrigEmSqUnits',
    'LanguageGroup',
    'DominantV',  # array
    'DominantH',  # array
    'FlexOK',  # string
    'BlueFuzz',
    'VCounterChars',  # counter
    'HCounterChars',  # counter
    'BaselineYCoord',
    'BaselineOvershoot',
    'CapHeight',
    'CapOvershoot',
    'LcHeight',
    'LcOvershoot',
    'AscenderHeight',
    'AscenderOvershoot',
    'FigHeight',
    'FigOvershoot',
    'Height5',
    'Height5Overshoot',
    'Height6',
    'Height6Overshoot',
    'DescenderOvershoot',
    'DescenderHeight',
    'SuperiorOvershoot',
    'SuperiorBaseline',
    'OrdinalOvershoot',
    'OrdinalBaseline',
    'Baseline5Overshoot',
    'Baseline5',
    'Baseline6Overshoot',
    'Baseline6',
]

integerPattern = """ -?\d+"""
arrayPattern = """ \[[ ,0-9]+\]"""
stringPattern = """ \S+"""
counterPattern = """ \([\S ]+\)"""

def printFontInfo(fontInfoString):
    for item in fontInfoKeywordList:
        if item in ['FontName', 'FlexOK']:
            matchingExp = item + stringPattern
        elif item in ['VCounterChars', 'HCounterChars']:
            matchingExp = item + counterPattern
        elif item in ['DominantV', 'DominantH']:
            matchingExp = item + arrayPattern
        else:
            matchingExp = item + integerPattern

        try:
            print('\t%s' % re.search(matchingExp, fontInfoString).group())
        except Exception:
            pass

def openFile(path, outFilePath, options):
    font_format = get_font_format(path)
    if font_format is None:
        raise ACFontError("{} is not a supported font format".format(path))

    if font_format == "UFO":
        font = openUFOFile(path, outFilePath, options)
    elif font_format in ("OTF", "CFF"):
        font = openOpenTypeFile(path, outFilePath, font_format, options)
    else:
        raise NotImplementedError("%s format is not supported yet, sorry." %
                                  font_format)

    return font

def openUFOFile(path, outFilePath, options):
    # If user has specified a path other than the source font path,
    # then copy the entire UFO font, and operate on the copy.
    if (outFilePath is not None) and (
       os.path.abspath(path) != os.path.abspath(outFilePath)):
        log.info("Copying from source UFO font to output UFO font "
                 "before processing...")
        if os.path.exists(outFilePath):
            shutil.rmtree(outFilePath)
        shutil.copytree(path, outFilePath)
        path = outFilePath
    # We always use the hash map to skip glyphs that have been previously
    # processed, unless the user has report only, not make changes.
    useHashMap = not options.logOnly
    font = UFOFontData(path, useHashMap, options.allowDecimalCoords,
                       kAutohintName)
    font.useProcessedLayer = True
    if options.writeToDefaultLayer:
        font.setWriteToDefault()
    # Programs in this list must be run before autohint,
    # if the outlines have been edited.
    font.requiredHistory.append(kCheckOutlineName)
    return font

def openOpenTypeFile(path, outFilePath, font_format, options):
    # If input font is CFF, build a dummy ttFont in memory.
    if font_format == "OTF":  # it is an OTF font, can process file directly
        ttFont = TTFont(path)
        if "CFF " not in ttFont:
            raise ACFontError("Font is not a CFF font <%s>." % path)
    elif font_format == "CFF":
        # now package the CFF font as an OTF font.
        with open(path, "rb") as ff:
            data = ff.read()

        ttFont = TTFont()
        cffClass = getTableClass('CFF ')
        ttFont['CFF '] = cffClass('CFF ')
        ttFont['CFF '].decompile(data, ttFont)
    else:
        raise ACFontError("Font file must be CFF or OTF file: %s." % path)

    fontData = CFFFontData(ttFont, path, outFilePath,
                           options.allowDecimalCoords, font_format)
    return fontData

def hintFiles(options):
    if options.reference_font:
        hintFile(options, options.reference_font, None, reference_master=True)
    for i, path in enumerate(options.inputPaths):
        outpath = None
        if options.outputPaths is not None and i < len(options.outputPaths):
            outpath = options.outputPaths[i]
        hintFile(options, path, outpath, reference_master=False)

def hintFile(options, path, outpath, reference_master):
    nameAliases = options.nameAliases

    fontFileName = os.path.basename(path)
    log.info("Hinting font %s. Start time: %s.", path, time.asctime())

    fontData = openFile(path, outpath, options)

    # filter specified list, if any, with font list.
    fontGlyphList = fontData.getGlyphList()
    glyphList = filterGlyphList(options, fontGlyphList, fontFileName)
    if not glyphList:
        raise ACFontError("Selected glyph list is empty for font <%s>." %
                          fontFileName)

    fontInfo = ""

    psName = fontData.getPSName()

    # Check counter glyphs, if any.
    if options.hCounterGlyphs or options.vCounterGlyphs:
        missingList = filter(lambda name: name not in fontGlyphList,
                             options.hCounterGlyphs + options.vCounterGlyphs)
        if missingList:
            log.error("H/VCounterChars glyph named in fontinfo is "
                      "not in font: %s", missingList)

    # Build alignment zone string
    if options.printDefaultFDDict:
        print("Showing default FDDict Values:")
        fdDict = fontData.getFontInfo(psName, path,
                                      options.allow_no_blues,
                                      options.noFlex,
                                      options.vCounterGlyphs,
                                      options.hCounterGlyphs)
        printFontInfo(str(fdDict))
        fontData.close()
        return

    fdGlyphDict, fontDictList = fontData.getfdInfo(psName, path,
                                                   options.allow_no_blues,
                                                   options.noFlex,
                                                   options.vCounterGlyphs,
                                                   options.hCounterGlyphs,
                                                   glyphList)

    if options.printFDDictList:
        # Print the user defined FontDicts, and exit.
        if fdGlyphDict:
            print("Showing user-defined FontDict Values:\n")
            for fi, fontDict in enumerate(fontDictList):
                print(fontDict.DictName)
                printFontInfo(str(fontDict))
                gnameList = []
                # item = [glyphName, [fdIndex, glyphListIndex]]
                itemList = sorted(fdGlyphDict.items(), key=lambda x: x[1][1])
                for gName, entry in itemList:
                    if entry[0] == fi:
                        gnameList.append(gName)
                print("%d glyphs:" % len(gnameList))
                if len(gnameList) > 0:
                    gTxt = " ".join(gnameList)
                else:
                    gTxt = "None"
                print(gTxt + "\n")
        else:
            print("There are no user-defined FontDict Values.")
        fontData.close()
        return

    if fdGlyphDict is None:
        fdDict = fontDictList[0]
        fontInfo = fdDict.getFontInfo()
    else:
        log.info("Using alternate FDDict global values from fontinfo "
                 "file for some glyphs.")

    # Get charstring for identifier in glyph-list
    isCID = fontData.isCID()
    lastFDIndex = None
    anyGlyphChanged = False
    if isCID:
        options.noFlex = True

    seenGlyphCount = 0
    processedGlyphCount = 0
    for name in glyphList:
        seenGlyphCount += 1

        # Convert to bez format
        bezString, width = fontData.convertToBez(name, options.hintAll)
        processedGlyphCount += 1
        if bezString is None:
            continue

        if "mt" not in bezString:
            # skip empty glyphs.
            continue
        # get new fontinfo string if FDarray index has changed,
        # as each FontDict has different alignment zones.
        gid = fontData.getGlyphID(name)
        if isCID:
            fdIndex = fontData.getfdIndex(gid)
            if not fdIndex == lastFDIndex:
                lastFDIndex = fdIndex
                fdDict = fontData.getFontInfo(psName, path,
                                              options.allow_no_blues,
                                              options.noFlex,
                                              options.vCounterGlyphs,
                                              options.hCounterGlyphs,
                                              fdIndex)
                fontInfo = fdDict.getFontInfo()
        else:
            if fdGlyphDict is not None:
                try:
                    fdIndex = fdGlyphDict[name][0]
                except KeyError:
                    # use default dict.
                    fdIndex = 0
                if lastFDIndex != fdIndex:
                    lastFDIndex = fdIndex
                    fdDict = fontDictList[fdIndex]
                    fontInfo = fdDict.getFontInfo()

        # Build autohint point list identifier
        oldBezString = ""
        oldHintBezString = ""

        if fdGlyphDict:
            log.info("%s: Begin hinting (using fdDict %s).",
                     nameAliases.get(name, name), fdDict.DictName)
        else:
            log.info("%s: Begin hinting.", nameAliases.get(name, name))

        # Call auto-hint library on bez string.
        if oldBezString != "" and oldBezString == bezString:
            newBezString = oldHintBezString
        else:
            if reference_master or not options.reference_font:
                newBezString = hint_bez_glyph(fontInfo, bezString,
                                              options.allowChanges,
                                              not options.noHintSub,
                                              options.allowDecimalCoords)
                options.baseMaster[name] = newBezString
            else:
                baseFontFileName = os.path.basename(options.reference_font)
                masters = [baseFontFileName, fontFileName]
                glyphs = [options.baseMaster[name], bezString]
                newBezString = hint_compatible_bez_glyphs(fontInfo, glyphs,
                                                          masters)
                newBezString = newBezString[1]  # FIXME

        if not newBezString:
            raise ACHintError(
                "%s Error - failure in processing outline data." %
                nameAliases.get(name, name))

        if not (("ry" in newBezString[:200]) or ("rb" in newBezString[:200]) or
           ("rm" in newBezString[:200]) or ("rv" in newBezString[:200])):
            log.info("No hints added!")

        if options.logOnly:
            continue

        # Convert bez to charstring, and update CFF.
        anyGlyphChanged = True
        fontData.updateFromBez(newBezString, name, width)

    if not options.logOnly:
        if anyGlyphChanged:
            log.info("Saving font file with new hints..." + time.asctime())
            fontData.saveChanges()
        else:
            fontData.close()
            log.info("No glyphs were hinted.")
    if processedGlyphCount != seenGlyphCount:
        log.info("Skipped %s of %s glyphs.",
                 seenGlyphCount - processedGlyphCount, seenGlyphCount)
    log.info("Done with font %s. End time: %s.", path, time.asctime())
<|endoftext|>